Classe: Utilizando XML como se fosse um arquivo INI
Bom, um tempo atrás eu encontrei um exemplo de código na net que mostrava como criar uma classe para utilizar um arquivo XML como um arquivo INI, ontem, resolvi mexer nele por necessidade e me deparei com algo que podia ser melhorado um pouco...
* [b:b927c0f285]Antes:[/b:b927c0f285] era bem básico, arquivo XML funcionava como [b:b927c0f285]1 único[/b:b927c0f285] arquivo INI, com funcoes de leitura e escrita de valores;
* [b:b927c0f285]Agora:[/b:b927c0f285] arquivo XML funciona com [b:b927c0f285]vários[/b:b927c0f285] arquivos INI aninhados em seu interior, adicionado um procedimento para importar novos arquivos INI para o corpo do XML. Adicionada funcoes/procedimentos de exclusão de INI, verificação e exclusão de sections e keys além de contadores diversos;
Um exemplo de utilização:
Um exemplo de importação:
Bom se alguém se interessar e quiser adicionar algo ou fazer alguma melhoria, segue a classe:
* [b:b927c0f285]Antes:[/b:b927c0f285] era bem básico, arquivo XML funcionava como [b:b927c0f285]1 único[/b:b927c0f285] arquivo INI, com funcoes de leitura e escrita de valores;
* [b:b927c0f285]Agora:[/b:b927c0f285] arquivo XML funciona com [b:b927c0f285]vários[/b:b927c0f285] arquivos INI aninhados em seu interior, adicionado um procedimento para importar novos arquivos INI para o corpo do XML. Adicionada funcoes/procedimentos de exclusão de INI, verificação e exclusão de sections e keys além de contadores diversos;
Um exemplo de utilização:
var ini: TINIXML; begin memo1.Clear; ini := TINIXML.Create(´meuINI.XML´); ini.INIfile := ´Config´; //seta o INI interno ou cria um novo caso nao haja ini.Backup := False; //realiza ou não backup do antigo arquivo ini.ValuesAsNode := True; //chaves como nós ou como parâmetros ini.WriteString(´section1´,´key1´,´valor´); Edit1.Text := ini.ReadString(´section1´,´key1´,´default´); ini.Free; end;
Um exemplo de importação:
var ini: TINIXML; begin ini := TINIXML.Create(´meuarquivo.XML´); //cria ou utiliza um existente ini.KeyAsNode := True; ini.ImportINI(´meu arquivo.INI´,´MeuINI´); // a importação seta o INI atual ini.ReadSections(memo1.Lines); ini.Free; end;
Bom se alguém se interessar e quiser adicionar algo ou fazer alguma melhoria, segue a classe:
unit uINIXml;
interface
uses
Forms, SysUtils, Windows, Classes, XmlIntf, XMLDoc, INIFiles;
type
TINIXML = class
private
FModified: Boolean;
FFileName: string;
FXMLDoc: TXMLDocument;
FBackup: Boolean;
FINIfile:string;
FAsNode: Boolean;
function GetVersion: string;
function GetINIfile: string;
function Up(const s:string):string;
procedure SetINIfile(const Value: string);
procedure CheckINIfile;
public
constructor Create(const FileName: string); overload;
constructor Create; overload;
destructor Destroy; override;
procedure Save;
function ReadString(const Section, Key, default: string): string;
procedure WriteString(const Section, Key, Value: string);
function ReadInteger(const Section, Key: string; default: Integer): Integer;
procedure WriteInteger(const Section, Key: string; Value: Integer);
function ReadBoolean(const Section, Key: string; default: Boolean): Boolean;
procedure WriteBoolean(const Section, Key: string; Value: Boolean);
procedure SaveNow;
//file
function XMLfile:string;
//delete
function EraseSection(const Section: string):boolean;
function DeleteKey(const Section,Key:string):boolean;
function EraseINI:boolean;
//verif
function SectionExists(const Section: string):boolean;
function KeyExists(const Section, Key: string):boolean;
procedure ReadINIfiles(Strings:TStrings);
procedure ReadSections(Strings:TStrings);
procedure ReadKeys(const Section:string; Strings:TStrings);
//counters
function countINIfiles:integer;
function countSections(const INIfile:string):integer; overload;
function countSections:integer; overload;
function countKeys(const INIfile,Section:string):integer; overload;
function countKeys(Section:string):integer; overload;
//import
function ImportINI(const fileName, InternalINIfile: string):boolean;
property Backup: Boolean read FBackup write FBackup;
property Version: string read GetVersion;
property INIfile: string read GetINIfile write SetINIfile;
property KeyAsNode: Boolean read FAsNode write FAsNode default False;
end;
implementation
{ TINIXML }
constructor TINIXML.Create(const FileName: string);
begin
inherited Create;
FBackup := True;
FFileName := FileName;
FXMLDoc := TXMLDocument.Create(Application);
FXMLDoc.Options := [doNodeAutoIndent];
FAsNode := False;
if FileExists(FFileName) then
FXMLDoc.LoadFromFile(FFileName)
else
begin
FXMLDoc.Active := True;
FXMLDoc.AddChild(´Configuration´);
end;
end;
constructor TINIXML.Create;
var fxml:string;
begin
fxml := ExtractFileExt(Application.Exename);
fxml := Copy(Application.Exename,1,length(Application.Exename)-length(fxml));
Create(fxml+´.xml´);
end;
destructor TINIXML.Destroy;
begin
Save;
FXMLDoc.Destroy;
inherited;
end;
function TINIXML.XMLfile: string;
begin
Result := FFileName;
end;
procedure TINIXML.CheckINIfile;
begin
if (not (Trim(FINIfile) <> ´´)) then raise Exception.Create(´Error: Empty Internal INI file!´);
end;
function TINIXML.EraseSection(const Section: string):boolean;
var
Node: IXMLNode;
begin
CheckINIfile;
Result := False;
Node := FXMLDoc.DocumentElement.ChildNodes.FindNode(FINIfile);
if Assigned(Node.ChildNodes.FindNode(Up(Section))) then
Result := Node.ChildNodes.Delete(Up(Section)) >= 0;
Node := nil;
if Result then
FModified := True;
end;
function TINIXML.DeleteKey(const Section, Key: string):boolean;
var
Node: IXMLNode;
begin
CheckINIfile;
Result := False;
Node := FXMLDoc.DocumentElement.ChildNodes.FindNode(FINIfile).ChildNodes.FindNode(Up(Section));;
if Assigned(Node) then
begin
if (Node.HasChildNodes) and (Node.ChildNodes.IndexOf(Up(Key))>=0) then
Result := Node.ChildNodes.Delete(Up(Section)) >= 0
else
Result := Node.AttributeNodes.Delete(Up(key)) >= 0;
end;
Node := nil;
if Result then
FModified := True;
end;
function TINIXML.EraseINI: boolean;
begin
CheckINIfile;
Result := False;
if Assigned(FXMLDoc.DocumentElement.ChildNodes.FindNode(FINIfile)) then
Result := FXMLDoc.DocumentElement.ChildNodes.Delete(FINIfile) >= 0;
if Result then
begin
FINIfile := EmptyStr;
FModified := True;
end;
end;
function TINIXML.GetINIfile: string;
begin
Result := FINIfile;
end;
function TINIXML.GetVersion: string;
begin
Result := ´1.00´;
end;
function TINIXML.ReadBoolean(const Section, Key: string; default: Boolean): Boolean;
begin
Result := Boolean(ReadInteger(Up(Section), Up(Key), Integer(default)));
end;
function TINIXML.ReadInteger(const Section, Key: string; default: Integer): Integer;
begin
Result := StrToInt(ReadString(Up(Section), Up(Key), IntToStr(default)));
end;
function TINIXML.ReadString(const Section, Key, default: string): string;
var
Node: IXMLNode;
begin
CheckINIfile;
Node := FXMLDoc.DocumentElement.ChildNodes.FindNode(FINIfile).ChildNodes.FindNode(Up(Section));
if Assigned(Node) then
begin
if Node.HasAttribute(Up(Key)) then
Result := Node.Attributes[Up(Key)]
else
if (Node.HasChildNodes) and (Node.ChildNodes.IndexOf(Up(Key))>=0) then
Result := Node.ChildNodes.Nodes[Node.ChildNodes.IndexOf(Up(Key))].NodeValue
else
Result := default;
end
else
Result := default;
Node := nil
end;
procedure TINIXML.Save;
begin
if not FModified then
Exit;
if FBackup then
CopyFile(PChar(FFileName), PChar(FFileName + ´.bak´), False);
FXMLDoc.SaveToFile(FFileName);
FModified := False;
end;
procedure TINIXML.SetINIfile(const Value: string);
begin
FINIfile := Up(Value);
if not Assigned(FXMLDoc.DocumentElement.ChildNodes.FindNode(FINIfile)) then
begin
if not FXMLDoc.Active then FXMLDoc.Active := True;
FXMLDoc.DocumentElement.AddChild(FINIfile);
end;
end;
function TINIXML.Up(const s: string): string;
begin
Result := StringReplace(AnsiUpperCase(s),´ ´,´´,[rfReplaceAll])
end;
procedure TINIXML.WriteBoolean(const Section, Key: string; Value: Boolean);
begin
WriteInteger(Up(Section), Up(Key), Integer(Value));
end;
procedure TINIXML.WriteInteger(const Section, Key: string; Value: Integer);
begin
WriteString(Up(Section), Up(Key), IntToStr(Value));
end;
procedure TINIXML.WriteString(const Section, Key, Value: string);
var
Node: IXMLNode;
begin
if ReadString(Up(Section), Up(Key), ´´) = Value then
Exit;
Node := FXMLDoc.DocumentElement.ChildNodes.FindNode(FINIfile).ChildNodes.FindNode(Up(Section));
if not Assigned(Node) then
Node := FXMLDoc.DocumentElement.ChildNodes.FindNode(FINIfile).AddChild(Up(Section));
if ((Node.HasAttribute(Up(Key))) or (not FAsNode)) and (not Assigned(Node.ChildNodes.FindNode(Up(Key)))) then
Node.Attributes[Up(Key)] := Value
else
begin
if not Assigned(Node.ChildNodes.FindNode(Up(Key))) then
Node.AddChild(Up(Key)).Text := Value
else
Node.ChildNodes.FindNode(Up(Key)).Text := Value;
end;
FModified := True;
Node := nil
end;
procedure TINIXML.SaveNow;
begin
FModified := True;
Save;
end;
function TINIXML.SectionExists(const Section: string): boolean;
begin
CheckINIfile;
Result := Assigned(FXMLDoc.DocumentElement.ChildNodes.FindNode(FINIfile).ChildNodes.FindNode(Up(Section)));
end;
function TINIXML.KeyExists(const Section, Key: string): boolean;
var
Node: IXMLNode;
begin
CheckINIfile;
Result := False;
Node := FXMLDoc.DocumentElement.ChildNodes.FindNode(FINIfile).ChildNodes.FindNode(Up(Section));
if Assigned(Node) then
begin
Result := Node.HasAttribute(Up(Key));
if (not Result) and (Node.HasChildNodes) then
Result := Assigned(Node.ChildNodes.FindNode(Up(Key)));
end;
Node := nil;
end;
procedure TINIXML.ReadINIfiles(Strings: TStrings);
var x:integer;
begin
Strings.Clear;
for x:=0 to pred(FXMLDoc.DocumentElement.ChildNodes.Count) do
Strings.Add(FXMLDoc.DocumentElement.ChildNodes[x].NodeName);
end;
procedure TINIXML.ReadSections(Strings: TStrings);
var
Node: IXMLNode;
x:longint;
begin
CheckINIfile;
Node := FXMLDoc.DocumentElement.ChildNodes.FindNode(FINIfile);
Strings.Clear;
if Assigned(Node) then
for x:=0 to pred(Node.ChildNodes.Count) do
begin
if Node.ChildNodes[x].NodeName[1] <> ´´ then
Strings.Add(Node.ChildNodes[x].NodeName);
end;
Node := nil;
end;
procedure TINIXML.ReadKeys(const Section: string; Strings: TStrings);
var
Node: IXMLNode;
x:longint;
begin
CheckINIfile;
Node := FXMLDoc.DocumentElement.ChildNodes.FindNode(FINIfile).ChildNodes.FindNode(Up(Section));
Strings.Clear;
if Assigned(Node) then
begin
for x:=0 to pred(Node.AttributeNodes.Count) do
Strings.Add(Node.AttributeNodes[x].NodeName);
for x:=0 to pred(Node.ChildNodes.Count) do
if Node.ChildNodes[x].NodeName[1] <> ´´ then
Strings.Add(Node.ChildNodes[x].NodeName);
end;
Node := nil;
end;
function TINIXML.ImportINI(const fileName, InternalINIfile: string): boolean;
var
//ini
lINIFile: TIniFile;
lINIname: string;
lSections, lItems: TStringList;
iSections, iItems: integer;
//xml
pXML,lNode: IXMLNode;
begin
Result := False;
lINIname := Up(InternalINIfile);
if Trim(lINIname) = EmptyStr then
raise Exception.Create(´Error: Empty INIname informed!´);
if not Assigned(FXMLDoc.DocumentElement.ChildNodes.FindNode(lINIname)) then
begin
if not FXMLDoc.Active then FXMLDoc.Active := True;
pXML := FXMLDoc.DocumentElement.AddChild(lINIname);
end
else
raise Exception.Create(´Error: Internal INIname already exists!´);
lINIFile := TIniFile.Create(FileName); try
lSections := TStringList.Create; try
lItems := TStringList.Create; try
lINIFile.ReadSections(lSections);
for iSections := 0 to pred(lSections.Count) do
begin
lItems.Clear;
lINIFile.ReadSection(lSections[iSections],lItems);
lNode := pXML.AddChild(StringReplace(lSections[iSections],´ ´,´´,[rfReplaceAll]));
for iItems := 0 to pred(lItems.Count) do
begin
if not FAsNode then
lNode.Attributes[lItems[iItems]] :=
lINIFile.ReadString(lSections[iSections],lItems[iItems],´´)
else
lNode.AddChild(lItems[iItems]).Text :=
lINIFile.ReadString(lSections[iSections],lItems[iItems],´´);
end;
lNode := nil;
pXML := nil;
FINIfile := lINIname;
FModified := True;
Save;
Result := True;
end;
finally lItems.Free; end;
finally lSections.Free; end;
finally lINIFile.Free; end;
end;
//COUNTERS
function TINIXML.countINIfiles: integer;
begin
Result := FXMLDoc.DocumentElement.ChildNodes.Count;
end;
function TINIXML.countSections(const INIfile:string): integer;
var
Node: IXMLNode;
begin
Node := FXMLDoc.DocumentElement.ChildNodes.FindNode(INIfile);
if Assigned(Node) then
Result := Node.ChildNodes.Count
else
Result := 0;
Node := nil;
end;
function TINIXML.countSections: integer;
var
Node: IXMLNode;
begin
CheckINIfile;
Node := FXMLDoc.DocumentElement.ChildNodes.FindNode(FINIfile);
if Assigned(Node) then
Result := Node.ChildNodes.Count
else
Result := 0;
Node := nil;
end;
function TINIXML.countKeys(const INIfile, Section: string): integer;
var
Node: IXMLNode;
auxi: integer;
begin
Node := FXMLDoc.DocumentElement.ChildNodes.FindNode(INIfile).ChildNodes.FindNode(Up(Section));
if Assigned(Node) then
begin
Result := Node.AttributeNodes.Count;
if Result = 0 then
for auxi := 0 to pred(Node.ChildNodes.Count) do
if Node.ChildNodes[auxi].NodeName[1] <> ´´ then
inc(Result);
end
else
Result := 0;
Node := nil;
end;
function TINIXML.countKeys(Section: string): integer;
var
Node: IXMLNode;
auxi:integer;
begin
CheckINIfile;
Node := FXMLDoc.DocumentElement.ChildNodes.FindNode(FINIfile).ChildNodes.FindNode(Up(Section));
if Assigned(Node) then
begin
Result := Node.AttributeNodes.Count;
if Result = 0 then
for auxi := 0 to pred(Node.ChildNodes.Count) do
if Node.ChildNodes[auxi].NodeName[1] <> ´´ then
inc(Result);
end
else
Result := 0;
Node := nil;
end;
end.
Richard Lima
Curtidas 0
Respostas
Richard Lima
31/03/2007
[b:a1c479efea]>>> Movendo nodes XML <<<[/b:a1c479efea]
Depois de estar utilizando um XML com a facilidade de um arquivo INI, tive a necessidade de reposicionar os INI internos, para isso, criei uma funcao de mover os nós do XML para cima ou para baixo, estendendo a funcionalidade para as sections e keys...
1 - criei um [b:a1c479efea]type[/b:a1c479efea] para a direção do movimento
2 - criei uma funcao na área private da classe
- implementação:
3 - adicionei 3 funcões na área public da classe
- implementação:
Exemplo:
[b:a1c479efea]XML:[/b:a1c479efea]
[b:a1c479efea]Código:[/b:a1c479efea]
[b:a1c479efea]Resultado XML:[/b:a1c479efea]
até!
Depois de estar utilizando um XML com a facilidade de um arquivo INI, tive a necessidade de reposicionar os INI internos, para isso, criei uma funcao de mover os nós do XML para cima ou para baixo, estendendo a funcionalidade para as sections e keys...
1 - criei um [b:a1c479efea]type[/b:a1c479efea] para a direção do movimento
type TINIXmlMoveDir = (moveDown,moveUp);
2 - criei uma funcao na área private da classe
function MoveNode(const Node: IXMLNode; moveDirection:TINIXmlMoveDir):boolean;
- implementação:
function TINIXML.MoveNode(const Node: IXMLNode; moveDirection:TINIXmlMoveDir):boolean; begin Result := False; case moveDirection of moveUp: if Node.PreviousSibling <> nil then Result := Node.ParentNode.DOMNode.insertBefore(Node.DOMNode,Node.PreviousSibling.DOMNode) <> nil; moveDown: if Node.NextSibling <> nil then if Node.NextSibling.NextSibling <> nil then Result := Node.ParentNode.DOMNode.insertBefore(Node.DOMNode,Node.NextSibling.NextSibling.DOMNode) <> nil else Result := Node.ParentNode.DOMNode.insertBefore(Node.NextSibling.DOMNode,Node.DOMNode) <> nil; end; end;
3 - adicionei 3 funcões na área public da classe
//move function MoveINI(const INIfile:string; moveDirection:TINIXmlMoveDir):boolean; function MoveSection(const Section:string; moveDirection:TINIXmlMoveDir):boolean; function MoveKey(const Section, Key: string; moveDirection:TINIXmlMoveDir):boolean;
- implementação:
function TINIXML.MoveINI(const INIfile: string; moveDirection: TINIXmlMoveDir):boolean; var Node: IXMLNode; begin Node := FXMLDoc.DocumentElement.ChildNodes.FindNode(Up(INIfile)); if Assigned(Node) then Result := MoveNode(Node,moveDirection); Node := nil; if Result then FModified := Result; end; function TINIXML.MoveSection(const Section:string; moveDirection:TINIXmlMoveDir):boolean; var Node: IXMLNode; begin CheckINIfile; Node := FXMLDoc.DocumentElement.ChildNodes.FindNode(FINIfile).ChildNodes.FindNode(Up(Section)); if Assigned(Node) then Result := MoveNode(Node,moveDirection); Node := nil; if Result then FModified := Result; end; function TINIXML.MoveKey(const Section, Key: string; moveDirection:TINIXmlMoveDir): boolean; var Node: IXMLNode; begin CheckINIfile; //only node keys Node := FXMLDoc.DocumentElement.ChildNodes.FindNode(FINIfile).ChildNodes.FindNode(Up(Section)).ChildNodes.FindNode(Up(Key)); if Assigned(Node) then Result := MoveNode(Node,moveDirection); Node := nil; if Result then FModified := Result; end;
Exemplo:
[b:a1c479efea]XML:[/b:a1c479efea]
<Configuration> <CONFIGURACAO> <SECTIONX> <KEY1>valor</KEY1> <KEY2>valor</KEY2> </SECTIONX> </CONFIGURACAO> </Configuration>
[b:a1c479efea]Código:[/b:a1c479efea]
var ini: TINIXML; begin ini := TINIXML.Create(´c:\meuINI.XML´); ini.INIfile := ´Configuracao´; Ini.MoveKey(´sectionx´,´key2´,moveUp); ini.Free; end;
[b:a1c479efea]Resultado XML:[/b:a1c479efea]
<Configuration> <CONFIGURACAO> <SECTIONX> <KEY2>valor</KEY2> <KEY1>valor</KEY1> </SECTIONX> </CONFIGURACAO> </Configuration>
até!
GOSTEI 0