xml sample/app settings in xml
can anyone help me to learn how to use XML. As a test i want to use XML instead of INI file开发者_开发问答s for saving a program settings.
Thanks
Rigo, you can use the IXMLDocument
interface or the TXMLDocument
object to interact with a XML document.
You can check these links for more information about XML and Delphi
- Creating, Parsing and Manipulating XML Documents with Delphi
- Xml Serialization - Basic Usage (Delphi 2010)
- Practical XML in Delphi (From @Jeroen)
Check this sample code , to learn the basics about xml management using the IXMLDocument
interface.
program Delphi_XmlSaveSettings;
{$APPTYPE CONSOLE}
uses
ActiveX,
SysUtils,
XmlDoc,
XmlIntf;
//this class mimic the basics functionalities of an TIniFile
//you can improve a lot the code adding exception handling and more methods for specifics tasks.
type
TXMLSettings = class
private
FFileName: string;
FXMLDoc: IXMLDocument; //Main XMLObject
public
constructor Create(const FileName: string); overload;
destructor Destroy; override;
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);
function ReadDouble(const Section, Key: string; default: Double): Double;
procedure WriteDouble(const Section, Key: string; Value: Double);
function ReadDateTime(const Section, Key: string; default: TDatetime): TDateTime;
procedure WriteDatetime(const Section, Key: string; Value: TDatetime);
function ReadDate(const Section, Key: string; default: TDatetime): TDateTime;
procedure WriteDate(const Section, Key: string; Value: TDatetime);
procedure Save;
end;
constructor TXMLSettings.Create(const FileName: string);
begin
inherited Create;
FFileName := FileName;
FXMLDoc := NewXMLDocument; //Create aNew instance of a XML Document
FXMLDoc.Encoding:= 'UTF-8'; //Set the encoding
FXMLDoc.Options := [doNodeAutoIndent];//optional, is used to indent the Xml document
if FileExists(FFileName) then
FXMLDoc.LoadFromFile(FFileName)
else
FXMLDoc.AddChild('Root'); //Create the root Node
end;
destructor TXMLSettings.Destroy;
begin
Save;
inherited;
end;
function TXMLSettings.ReadBoolean(const Section, Key: string; default: Boolean): Boolean;
begin
Result := Boolean(ReadInteger(Section, Key, Integer(default)));
end;
function TXMLSettings.ReadDate(const Section, Key: string; default: TDatetime): TDateTime;
begin
Result := StrToDate(ReadString(Section, Key, DateToStr(default)));
end;
function TXMLSettings.ReadDateTime(const Section, Key: string; default: TDatetime): TDateTime;
begin
Result := StrToDateTime(ReadString(Section, Key, DateTimeToStr(default)));
end;
function TXMLSettings.ReadDouble(const Section, Key: string; default: Double): Double;
begin
Result := StrToFloat(ReadString(Section, Key, FloatToStr(default)));
end;
function TXMLSettings.ReadInteger(const Section, Key: string; default: Integer): Integer;
begin
Result := StrToInt(ReadString(Section, Key, IntToStr(default)));
end;
function TXMLSettings.ReadString(const Section, Key, default: string): string;
var
XMLNode: IXMLNode;
begin
XMLNode := FXMLDoc.DocumentElement.ChildNodes.FindNode(Section);
if Assigned(XMLNode) and XMLNode.HasAttribute(Key) then //Check if exist the Key
Result := XMLNode.Attributes[Key]
else
Result := default;
end;
procedure TXMLSettings.Save;
begin
FXMLDoc.SaveToFile(FFileName);
end;
procedure TXMLSettings.WriteBoolean(const Section, Key: string; Value: Boolean);
begin
WriteInteger(Section, Key, Integer(Value));
end;
procedure TXMLSettings.WriteDate(const Section, Key: string; Value: TDatetime);
begin
WriteString(Section, Key, DateToStr(Value));
end;
procedure TXMLSettings.WriteDatetime(const Section, Key: string; Value: TDatetime);
begin
WriteString(Section, Key, DateTimeToStr(Value));
end;
procedure TXMLSettings.WriteDouble(const Section, Key: string; Value: Double);
begin
WriteString(Section, Key, FloatToStr(Value));
end;
procedure TXMLSettings.WriteInteger(const Section, Key: string; Value: Integer);
begin
WriteString(Section, Key, IntToStr(Value));
end;
procedure TXMLSettings.WriteString(const Section, Key, Value: string);
var
XMLNode: IXMLNode;
begin
XMLNode := FXMLDoc.DocumentElement.ChildNodes.FindNode(Section);
if not Assigned(XMLNode) then
XMLNode := FXMLDoc.DocumentElement.AddChild(Section);
XMLNode.Attributes[Key] := Value;
end;
Procedure SaveSettings; //Store the settings
Var
AppSettings : TXMLSettings;
begin
AppSettings:=TXMLSettings.Create(ExtractFilePath(ParamStr(0))+'MySettings.xml');
try
AppSettings.WriteString('Server','Type','SQLServer');
AppSettings.WriteString('Server','User','root');
AppSettings.WriteInteger('Server','port',1433);
AppSettings.WriteString('Server','IP','192.168.1.1');
AppSettings.WriteString('Server','Database','Prod');
AppSettings.WriteBoolean('Server','WindowsAuth',False);
AppSettings.WriteDouble('Server','Latency',25.90892);
AppSettings.WriteDatetime('Server','LastAccess',Now);
AppSettings.WriteDate('Server','ActualDate',Now);
AppSettings.Save;
finally
AppSettings.Free;
end;
Writeln('Settings Saved');
end;
Procedure ShowSettings;//Read the settings
Var
AppSettings : TXMLSettings;
begin
AppSettings:=TXMLSettings.Create(ExtractFilePath(ParamStr(0))+'MySettings.xml');
try
Writeln(Format('Type %s',[AppSettings.ReadString('Server','Type','')]));
Writeln(Format('Port %d',[AppSettings.ReadInteger('Server','port',0)]));
Writeln(Format('IP %s',[AppSettings.ReadString('Server','IP','')]));
Writeln(Format('Database %s',[AppSettings.ReadString('Server','Database','')]));
Writeln(Format('WindowsAuth %s',[BoolToStr(AppSettings.ReadBoolean('Server','WindowsAuth',True),True)]));
Writeln(Format('Latency %g',[AppSettings.ReadDouble('Server','Latency',0)]));
Writeln(Format('LastAccess %s',[DateTimeToStr(AppSettings.ReadDateTime('Server','LastAccess',Now-1))]));
Writeln(Format('ActualDate %s',[DateToStr(AppSettings.ReadDate('Server','ActualDate',Now-1))]));
finally
AppSettings.Free;
end;
end;
begin
try
CoInitialize(nil); //only necesary in console applications
try
SaveSettings; //Save the sample settings
ShowSettings; //Read the stored settings
Readln;
finally
CoUninitialize; //only necesary in console applications
end;
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
end.
I think RRUZ mostly got it all.
You can also look at SimpleStorage because it was made just with task like this in mind. I use it for all my program settings manipulation. For example here is one of such examples I use (you can see it simplifies code because you don't need to check if a node or a value exist):
The XML:
<Settings>
<Service>
<Name>*********</Name>
<DisplayName>*********</DisplayName>
<Description>************</Description>
</Service>
<Http>
<ListenQueue>1000</ListenQueue>
<Port>8778</Port>
</Http>
<IPC>
<Name>*******</Name>
</IPC>
<Modules>
<Default>
<Protocol>ISAPI</Protocol>
<MaxProcNum>5</MaxProcNum>
<MemoryLimit>500</MemoryLimit>
</Default>
</Modules>
</Settings>
And The code:
procedure THydraSettings.LoadSettings(const RootPath: string);
var
Settings: ISimpleStorage;
DefaulNode: IElement;
DefExtDir: string;
begin
DefExtDir := ExtractFilePath(ParamStr(0)) + DIR_EXTENSIONS;
Settings := StorageFromFile(RootPath + XML_SettingsFile);
FExtensionsDir := Settings.Get(cNode_Extensions).AsStringDef(DefExtDir);
FExtensionsDir := IncludeTrailingPathDelimiter(FExtensionsDir);
// IPC server based settings
FIPC.Name := Settings.Get(cNode_IPCName).AsStringDef('AI_Hydra');
// http server based settings
FHTTP.ServerPort := Settings.Get(cNode_HttpPort).AsIntegerDef(80);
FHTTP.ListenQueue := Settings.Get(cNode_ListenQueue).AsIntegerDef(100);
// get the defaults settings for modules
DefaulNode := Settings.Get([cNode_Modules, cNode_Default]);
FProtocol := DefaulNode.Get(cNode_Protocol).AsStringDef('ISAPI');
FMaxProcNum := DefaulNode.Get(cNode_MaxProcNum).AsIntegerDef(5);
FMemoryLimit := DefaulNode.Get(cNode_MemoryLimit).AsIntegerDef;
FTimeout := DefaulNode.Get(cNode_MemoryLimit).AsIntegerDef(30);
FUnload := DefaulNode.Get(cNode_Unload).AsBooleanDef;
end;
In recent versions of Delphi, 2009+ I believe, there is a unit called XMLIniFile which contains an xml wrapper around TIniFile called TXMLIniFile, and also TXMLMemIniFile.
However in my installation of Delphi 2010 XMLIniFile.pas is missing and only XMLIniFile.dcu is present, you can still use it of course though. In addition it seems to be undocumented, even on the Delphi DocWiki.
The open source Jedi VCL library contains a TJvAppXMLFileStorage class (in unit JvAppXMLStorage) which stores the settings in a XML file.
TJvAppXMLFileStorage is a data storage backend that stores the data in an XML file.
As a descendant of TJvCustomAppXMLStorage it provides the standard interface for storing data (such as settings, form positions and sizes, etc) in a XML file format. This data will be stored in an actual file, represented in memory through the use of a TJvSimpleXML object.
Depending on which edition of Delphi you are using, you may or may not have the TXMLDocument component available. If you do not, then you will have to use a third-party XML library/component. I prefer libxml2 myself, and it has a binding available for Pascal/Delphi.
From swissdelphicenter
http://www.swissdelphicenter.ch/torry/showcode.php?id=2269
{This code shows how to use TXMLDocument to save and restore configuration
settings in a XML document. The public methods works the same as a TIniFile.
There is not mutch comment in the code because it is self explaining
and small. Hope this benefit other persons. It is only tested in D7 pro.}
unit uCiaXml;
interface
uses
Forms, SysUtils, Windows, XmlIntf, XMLDoc;
type
TXMLConfig = class
private
FModified: Boolean;
FFileName: string;
FXMLDoc: TXMLDocument;
FBackup: Boolean;
function GetVersion: string;
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);
property Backup: Boolean read FBackup write FBackup;
property Version: string read GetVersion;
end;
implementation
{ TXMLConfig }
constructor TXMLConfig.Create(const FileName: string);
begin
inherited Create;
FBackup := True;
FFileName := FileName;
FXMLDoc := TXMLDocument.Create(Application);
FXMLDoc.Options := [doNodeAutoIndent];
if FileExists(FFileName) then
FXMLDoc.LoadFromFile(FFileName)
else
begin
FXMLDoc.Active := True;
FXMLDoc.AddChild('Configuration');
end;
end;
constructor TXMLConfig.Create;
begin
Create(ChangeFileExt(Application.Exename, '_cfg.xml'));
end;
destructor TXMLConfig.Destroy;
begin
Save;
FXMLDoc.Destroy;
inherited;
end;
function TXMLConfig.GetVersion: string;
begin
Result := '1.00';
end;
function TXMLConfig.ReadBoolean(const Section, Key: string; default: Boolean): Boolean;
begin
Result := Boolean(ReadInteger(Section, Key, Integer(default)));
end;
function TXMLConfig.ReadInteger(const Section, Key: string; default: Integer): Integer;
begin
Result := StrToInt(ReadString(Section, Key, IntToStr(default)));
end;
function TXMLConfig.ReadString(const Section, Key, default: string): string;
var
Node: IXMLNode;
begin
Node := FXMLDoc.DocumentElement.ChildNodes.FindNode(Section);
if Assigned(Node) and Node.HasAttribute(Key) then
Result := Node.Attributes[Key]
else
Result := default;
end;
procedure TXMLConfig.Save;
begin
if not FModified then
Exit;
if FBackup then
CopyFile(PChar(FFileName), PChar(FFileName + '.bak'), False);
FXMLDoc.SaveToFile(FFileName);
FModified := False;
end;
procedure TXMLConfig.WriteBoolean(const Section, Key: string; Value: Boolean);
begin
WriteInteger(Section, Key, Integer(Value));
end;
procedure TXMLConfig.WriteInteger(const Section, Key: string; Value: Integer);
begin
WriteString(Section, Key, IntToStr(Value));
end;
procedure TXMLConfig.WriteString(const Section, Key, Value: string);
var
Node: IXMLNode;
begin
if ReadString(Section, Key, '') = Value then
Exit;
Node := FXMLDoc.DocumentElement.ChildNodes.FindNode(Section);
if not Assigned(Node) then
Node := FXMLDoc.DocumentElement.AddChild(Section);
Node.Attributes[Key] := Value;
FModified := True;
end;
end.
To store configuration in a XML file, you can use the OmniXML library. It's pretty simple to use with TPersistent derivates:
lets say:
type
TConfig = class(TPersistent)
private
FSomeOption: string;
published
SomeOption: string read FSomeOption write FSomeOption;
end;
then, with a single line of code you can store it to a xml file:
begin
TOmniXMLWriter.SaveToFile(Config, ConfigFileName, pfNodes, ofIndent)
end;
where Config is a instance of TConfig.
You can read a bit more about this in my blog (translated from Spanish with Google)
Best regards.
VerySimpleXML may also fit for such requirement : handling of configuration file.
It has a small footprint above all.
精彩评论