2011-02-18 15:51:00 +01:00
|
|
|
{
|
|
|
|
:: X2UtPersistXML implements persistency to an XML file.
|
|
|
|
::
|
|
|
|
:: Last changed: $Date$
|
|
|
|
:: Revision: $Rev$
|
|
|
|
:: Author: $Author$
|
|
|
|
}
|
|
|
|
unit X2UtPersistXML;
|
|
|
|
|
|
|
|
{$WARN SYMBOL_PLATFORM OFF}
|
|
|
|
|
|
|
|
interface
|
|
|
|
uses
|
|
|
|
Classes,
|
|
|
|
Registry,
|
|
|
|
Windows,
|
|
|
|
|
|
|
|
X2UtPersist,
|
|
|
|
X2UtPersistIntf,
|
|
|
|
X2UtPersistXMLBinding;
|
|
|
|
|
|
|
|
|
|
|
|
type
|
|
|
|
TX2UtPersistXML = class(TX2CustomPersist)
|
|
|
|
private
|
|
|
|
FFileName: String;
|
|
|
|
protected
|
|
|
|
function CreateFiler(AIsReader: Boolean): IX2PersistFiler; override;
|
|
|
|
public
|
|
|
|
property FileName: String read FFileName write FFileName;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
TX2UtPersistXMLFiler = class(TX2CustomPersistFiler)
|
|
|
|
private
|
|
|
|
FFileName: String;
|
|
|
|
FConfiguration: IXMLConfiguration;
|
2014-03-16 09:42:46 +01:00
|
|
|
FIsReader: Boolean;
|
2011-02-18 15:51:00 +01:00
|
|
|
FSection: IXMLSection;
|
|
|
|
FSectionStack: TInterfaceList;
|
|
|
|
protected
|
2011-03-07 10:05:09 +01:00
|
|
|
function GetValue(const AName: string; out AValue: IXMLvalue; AWriting: Boolean): Boolean;
|
2011-02-18 15:51:00 +01:00
|
|
|
public
|
|
|
|
function BeginSection(const AName: String): Boolean; override;
|
|
|
|
procedure EndSection; override;
|
|
|
|
|
|
|
|
|
|
|
|
procedure GetKeys(const ADest: TStrings); override;
|
|
|
|
procedure GetSections(const ADest: TStrings); override;
|
|
|
|
|
|
|
|
|
|
|
|
function ReadInteger(const AName: String; out AValue: Integer): Boolean; override;
|
|
|
|
function ReadFloat(const AName: String; out AValue: Extended): Boolean; override;
|
|
|
|
function ReadString(const AName: String; out AValue: String): Boolean; override;
|
|
|
|
function ReadInt64(const AName: String; out AValue: Int64): Boolean; override;
|
2011-03-07 10:05:09 +01:00
|
|
|
function ReadVariant(const AName: string; out AValue: Variant): Boolean; override;
|
2011-02-18 15:51:00 +01:00
|
|
|
|
|
|
|
function ReadStream(const AName: string; AStream: TStream): Boolean; override;
|
|
|
|
|
|
|
|
|
|
|
|
function WriteInteger(const AName: String; AValue: Integer): Boolean; override;
|
|
|
|
function WriteFloat(const AName: String; AValue: Extended): Boolean; override;
|
|
|
|
function WriteString(const AName, AValue: String): Boolean; override;
|
|
|
|
function WriteInt64(const AName: String; AValue: Int64): Boolean; override;
|
2011-03-07 10:05:09 +01:00
|
|
|
function WriteVariant(const AName: Variant; const AValue: Variant): Boolean; override;
|
2011-02-18 15:51:00 +01:00
|
|
|
|
|
|
|
function WriteStream(const AName: string; AStream: TStream): Boolean; override;
|
|
|
|
|
2011-03-07 10:05:09 +01:00
|
|
|
|
2011-02-18 15:51:00 +01:00
|
|
|
procedure DeleteKey(const AName: string); override;
|
|
|
|
procedure DeleteSection(const AName: string); override;
|
|
|
|
|
|
|
|
|
|
|
|
property Configuration: IXMLConfiguration read FConfiguration;
|
2014-03-16 09:42:46 +01:00
|
|
|
property IsReader: Boolean read FIsReader;
|
2011-02-18 15:51:00 +01:00
|
|
|
property Section: IXMLSection read FSection;
|
|
|
|
property SectionStack: TInterfaceList read FSectionStack;
|
|
|
|
property FileName: String read FFileName;
|
|
|
|
public
|
|
|
|
constructor Create(AIsReader: Boolean; const AFileName: String);
|
|
|
|
destructor Destroy; override;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
{ Wrapper functions }
|
|
|
|
function ReadFromXML(AObject: TObject; const AFileName: string): Boolean;
|
|
|
|
procedure WriteToXML(AObject: TObject; const AFileName: string);
|
|
|
|
|
|
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
|
|
SysUtils,
|
2011-03-07 10:05:09 +01:00
|
|
|
Variants,
|
2011-02-18 15:51:00 +01:00
|
|
|
|
|
|
|
X2UtStrings;
|
|
|
|
|
|
|
|
|
|
|
|
{ Wrapper functions }
|
|
|
|
function ReadFromXML(AObject: TObject; const AFileName: string): Boolean;
|
|
|
|
begin
|
|
|
|
with TX2UtPersistXML.Create do
|
|
|
|
try
|
|
|
|
FileName := AFileName;
|
|
|
|
Result := Read(AObject);
|
|
|
|
finally
|
|
|
|
Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure WriteToXML(AObject: TObject; const AFileName: string);
|
|
|
|
begin
|
|
|
|
with TX2UtPersistXML.Create do
|
|
|
|
try
|
|
|
|
FileName := AFileName;
|
|
|
|
Write(AObject);
|
|
|
|
finally
|
|
|
|
Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
{ TX2UtPersistXML }
|
|
|
|
function TX2UtPersistXML.CreateFiler(AIsReader: Boolean): IX2PersistFiler;
|
|
|
|
begin
|
|
|
|
Result := TX2UtPersistXMLFiler.Create(AIsReader, Self.FileName);
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
{ TX2UtPersistXML }
|
|
|
|
constructor TX2UtPersistXMLFiler.Create(AIsReader: Boolean; const AFileName: string);
|
|
|
|
begin
|
|
|
|
inherited Create(AIsReader);
|
|
|
|
|
|
|
|
FSectionStack := TInterfaceList.Create;
|
|
|
|
FFileName := AFileName;
|
2014-03-16 09:42:46 +01:00
|
|
|
FIsReader := AIsReader;
|
2011-02-18 15:51:00 +01:00
|
|
|
|
|
|
|
if AIsReader then
|
|
|
|
FConfiguration := LoadConfiguration(AFileName)
|
|
|
|
else
|
|
|
|
FConfiguration := NewConfiguration;
|
|
|
|
|
|
|
|
FSection := FConfiguration;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
destructor TX2UtPersistXMLFiler.Destroy;
|
|
|
|
begin
|
|
|
|
if not IsReader then
|
|
|
|
Configuration.OwnerDocument.SaveToFile(FileName);
|
|
|
|
|
|
|
|
FreeAndNil(FSectionStack);
|
|
|
|
|
|
|
|
inherited;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
function TX2UtPersistXMLFiler.BeginSection(const AName: String): Boolean;
|
|
|
|
var
|
|
|
|
sectionIndex: Integer;
|
|
|
|
|
|
|
|
begin
|
|
|
|
Result := False;
|
|
|
|
|
|
|
|
for sectionIndex := 0 to Pred(Section.section.Count) do
|
|
|
|
begin
|
|
|
|
if SameText(Section.section[sectionIndex].name, AName) then
|
|
|
|
begin
|
|
|
|
Result := True;
|
|
|
|
FSection := Section.section[sectionIndex];
|
|
|
|
Break;;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-03-16 09:42:46 +01:00
|
|
|
if (not Result) and (not IsReader) then
|
2011-02-18 15:51:00 +01:00
|
|
|
begin
|
|
|
|
FSection := Section.section.Add;
|
|
|
|
FSection.name := AName;
|
|
|
|
Result := True;
|
|
|
|
end;
|
|
|
|
|
|
|
|
if Result then
|
|
|
|
begin
|
|
|
|
SectionStack.Add(Section);
|
|
|
|
inherited BeginSection(AName);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TX2UtPersistXMLFiler.EndSection;
|
2011-02-18 15:57:31 +01:00
|
|
|
var
|
|
|
|
lastItem: Integer;
|
|
|
|
|
2011-02-18 15:51:00 +01:00
|
|
|
begin
|
|
|
|
inherited;
|
|
|
|
|
|
|
|
if SectionStack.Count > 0 then
|
|
|
|
begin
|
2011-02-18 15:56:22 +01:00
|
|
|
lastItem := Pred(SectionStack.Count);
|
2011-02-18 15:59:12 +01:00
|
|
|
|
2011-03-07 10:05:09 +01:00
|
|
|
if lastItem > 0 then
|
|
|
|
FSection := (SectionStack[Pred(lastItem)] as IXMLSection)
|
2011-02-18 15:59:12 +01:00
|
|
|
else
|
2011-03-07 10:05:09 +01:00
|
|
|
FSection := Configuration;
|
|
|
|
|
2011-02-18 15:56:22 +01:00
|
|
|
SectionStack.Delete(lastItem);
|
2011-02-18 15:51:00 +01:00
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TX2UtPersistXMLFiler.GetKeys(const ADest: TStrings);
|
|
|
|
var
|
|
|
|
valueIndex: Integer;
|
|
|
|
|
|
|
|
begin
|
|
|
|
for valueIndex := 0 to Pred(Section.value.Count) do
|
|
|
|
ADest.Add(Section.value[valueIndex].name);
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TX2UtPersistXMLFiler.GetSections(const ADest: TStrings);
|
|
|
|
var
|
|
|
|
sectionIndex: Integer;
|
|
|
|
|
|
|
|
begin
|
|
|
|
for sectionIndex := 0 to Pred(Section.section.Count) do
|
|
|
|
ADest.Add(Section.section[sectionIndex].name);
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2011-03-07 10:05:09 +01:00
|
|
|
function TX2UtPersistXMLFiler.GetValue(const AName: string; out AValue: IXMLvalue; AWriting: Boolean): Boolean;
|
2011-02-18 15:51:00 +01:00
|
|
|
var
|
|
|
|
valueIndex: Integer;
|
|
|
|
|
|
|
|
begin
|
2011-03-07 10:05:09 +01:00
|
|
|
AValue := nil;
|
2011-02-18 15:51:00 +01:00
|
|
|
Result := False;
|
|
|
|
|
|
|
|
for valueIndex := 0 to Pred(Section.value.Count) do
|
|
|
|
if SameText(Section.value[valueIndex].name, AName) then
|
|
|
|
begin
|
2011-03-07 10:05:09 +01:00
|
|
|
AValue := Section.value[valueIndex];
|
2011-02-18 15:51:00 +01:00
|
|
|
Result := True;
|
2011-03-07 10:05:09 +01:00
|
|
|
Break;
|
2011-02-18 15:51:00 +01:00
|
|
|
end;
|
2011-03-07 10:05:09 +01:00
|
|
|
|
|
|
|
if AWriting then
|
|
|
|
begin
|
|
|
|
if not Result then
|
|
|
|
begin
|
|
|
|
AValue := Section.value.Add;
|
|
|
|
AValue.name := AName;
|
|
|
|
end;
|
|
|
|
|
|
|
|
AValue.ChildNodes.Clear;
|
|
|
|
Result := True;
|
|
|
|
end;
|
2011-02-18 15:51:00 +01:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
function TX2UtPersistXMLFiler.ReadInteger(const AName: String; out AValue: Integer): Boolean;
|
|
|
|
var
|
2011-03-07 10:05:09 +01:00
|
|
|
value: IXMLvalue;
|
2011-02-18 15:51:00 +01:00
|
|
|
|
|
|
|
begin
|
2011-03-07 10:05:09 +01:00
|
|
|
Result := GetValue(AName, value, False) and (value.Hasinteger);
|
|
|
|
if Result then
|
|
|
|
AValue := value.integer;
|
2011-02-18 15:51:00 +01:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
function TX2UtPersistXMLFiler.ReadFloat(const AName: String; out AValue: Extended): Boolean;
|
|
|
|
var
|
2011-03-07 10:05:09 +01:00
|
|
|
value: IXMLvalue;
|
2011-02-18 15:51:00 +01:00
|
|
|
|
|
|
|
begin
|
2011-03-07 10:05:09 +01:00
|
|
|
Result := GetValue(AName, value, False) and (value.Hasfloat);
|
|
|
|
if Result then
|
|
|
|
AValue := value.float;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
function TX2UtPersistXMLFiler.ReadVariant(const AName: string; out AValue: Variant): Boolean;
|
|
|
|
var
|
|
|
|
value: IXMLvalue;
|
|
|
|
|
|
|
|
begin
|
2011-03-29 11:05:11 +02:00
|
|
|
Result := GetValue(AName, value, False);
|
2011-03-07 10:05:09 +01:00
|
|
|
if Result then
|
|
|
|
begin
|
2011-03-29 11:05:11 +02:00
|
|
|
if value.Hasinteger then
|
|
|
|
AValue := value.integer
|
|
|
|
|
|
|
|
else if value.Hasfloat then
|
|
|
|
AValue := value.float
|
|
|
|
|
|
|
|
else if value.Has_string then
|
|
|
|
AValue := value._string
|
|
|
|
|
|
|
|
else if value.Hasint64 then
|
|
|
|
AValue := value.int64
|
|
|
|
|
|
|
|
else if value.Hasvariant then
|
|
|
|
if value.variantIsNil then
|
|
|
|
AValue := Null
|
|
|
|
else
|
|
|
|
AValue := value.variant;
|
2011-03-07 10:05:09 +01:00
|
|
|
end;
|
2011-02-18 15:51:00 +01:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
function TX2UtPersistXMLFiler.ReadStream(const AName: string; AStream: TStream): Boolean;
|
|
|
|
begin
|
|
|
|
raise EAbstractError.Create('Stream not yet supported in XML');
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
function TX2UtPersistXMLFiler.ReadString(const AName: String; out AValue: String): Boolean;
|
|
|
|
var
|
2011-03-07 10:05:09 +01:00
|
|
|
value: IXMLvalue;
|
2011-02-18 15:51:00 +01:00
|
|
|
|
|
|
|
begin
|
2011-03-07 10:05:09 +01:00
|
|
|
Result := GetValue(AName, value, False) and (value.Has_string);
|
|
|
|
if Result then
|
|
|
|
AValue := value._string;
|
2011-02-18 15:51:00 +01:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
function TX2UtPersistXMLFiler.ReadInt64(const AName: String; out AValue: Int64): Boolean;
|
|
|
|
var
|
2011-03-07 10:05:09 +01:00
|
|
|
value: IXMLvalue;
|
2011-02-18 15:51:00 +01:00
|
|
|
|
|
|
|
begin
|
2011-03-07 10:05:09 +01:00
|
|
|
Result := GetValue(AName, value, False) and (value.Hasint64);
|
|
|
|
if Result then
|
|
|
|
AValue := value.int64;
|
2011-02-18 15:51:00 +01:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
2011-03-07 10:05:09 +01:00
|
|
|
function TX2UtPersistXMLFiler.WriteInteger(const AName: String; AValue: Integer): Boolean;
|
2011-02-18 15:51:00 +01:00
|
|
|
var
|
|
|
|
value: IXMLvalue;
|
|
|
|
|
|
|
|
begin
|
2011-03-07 10:05:09 +01:00
|
|
|
Result := GetValue(AName, value, True);
|
|
|
|
if Result then
|
|
|
|
value.integer := AValue;
|
2011-02-18 15:51:00 +01:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
2011-03-07 10:05:09 +01:00
|
|
|
function TX2UtPersistXMLFiler.WriteFloat(const AName: String; AValue: Extended): Boolean;
|
|
|
|
var
|
|
|
|
value: IXMLvalue;
|
|
|
|
|
2011-02-18 15:51:00 +01:00
|
|
|
begin
|
2011-03-07 10:05:09 +01:00
|
|
|
Result := GetValue(AName, value, True);
|
|
|
|
if Result then
|
|
|
|
value.float := AValue;
|
2011-02-18 15:51:00 +01:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
2011-03-07 10:05:09 +01:00
|
|
|
function TX2UtPersistXMLFiler.WriteString(const AName, AValue: String): Boolean;
|
|
|
|
var
|
|
|
|
value: IXMLvalue;
|
|
|
|
|
2011-02-18 15:51:00 +01:00
|
|
|
begin
|
2011-03-07 10:05:09 +01:00
|
|
|
Result := GetValue(AName, value, True);
|
|
|
|
if Result then
|
|
|
|
value._string := AValue;
|
2011-02-18 15:51:00 +01:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
2011-03-07 10:05:09 +01:00
|
|
|
function TX2UtPersistXMLFiler.WriteInt64(const AName: String; AValue: Int64): Boolean;
|
|
|
|
var
|
|
|
|
value: IXMLvalue;
|
|
|
|
|
2011-02-18 15:51:00 +01:00
|
|
|
begin
|
2011-03-07 10:05:09 +01:00
|
|
|
Result := GetValue(AName, value, True);
|
|
|
|
if Result then
|
|
|
|
value.int64 := AValue;
|
2011-02-18 15:51:00 +01:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
2011-03-07 10:05:09 +01:00
|
|
|
function TX2UtPersistXMLFiler.WriteVariant(const AName, AValue: Variant): Boolean;
|
|
|
|
var
|
|
|
|
value: IXMLvalue;
|
|
|
|
|
2011-02-18 15:51:00 +01:00
|
|
|
begin
|
2011-03-07 10:05:09 +01:00
|
|
|
Result := GetValue(AName, value, True);
|
|
|
|
if Result then
|
|
|
|
begin
|
|
|
|
if VarIsNull(AValue) or VarIsClear(AValue) then
|
|
|
|
value.variantIsNil := True
|
|
|
|
else
|
2011-03-29 11:05:11 +02:00
|
|
|
begin
|
|
|
|
case VarType(AValue) of
|
|
|
|
varSmallint,
|
|
|
|
varInteger:
|
|
|
|
value.Integer := AValue;
|
|
|
|
|
|
|
|
varSingle,
|
|
|
|
varDouble,
|
2011-03-29 12:15:45 +02:00
|
|
|
varCurrency,
|
|
|
|
varDate:
|
2011-03-29 11:05:11 +02:00
|
|
|
value.float := AValue;
|
|
|
|
|
|
|
|
varInt64:
|
|
|
|
value.Int64 := AValue;
|
|
|
|
|
|
|
|
varOleStr,
|
|
|
|
varStrArg,
|
|
|
|
varString:
|
|
|
|
value._string := AValue;
|
|
|
|
else
|
|
|
|
value.variant := AValue;
|
|
|
|
end;
|
|
|
|
end;
|
2011-03-07 10:05:09 +01:00
|
|
|
end;
|
2011-02-18 15:51:00 +01:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
2011-03-07 10:05:09 +01:00
|
|
|
function TX2UtPersistXMLFiler.WriteStream(const AName: string; AStream: TStream): Boolean;
|
2011-02-18 15:51:00 +01:00
|
|
|
begin
|
2011-03-07 10:05:09 +01:00
|
|
|
raise EAbstractError.Create('Stream not yet supported in XML');
|
2011-02-18 15:51:00 +01:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TX2UtPersistXMLFiler.DeleteKey(const AName: string);
|
|
|
|
var
|
|
|
|
valueIndex: Integer;
|
|
|
|
|
|
|
|
begin
|
|
|
|
for valueIndex := 0 to Pred(Section.value.Count) do
|
|
|
|
if SameText(Section.value[valueIndex].name, AName) then
|
|
|
|
begin
|
|
|
|
Section.value.Delete(valueIndex);
|
|
|
|
Break;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TX2UtPersistXMLFiler.DeleteSection(const AName: string);
|
|
|
|
var
|
|
|
|
sectionIndex: Integer;
|
|
|
|
|
|
|
|
begin
|
|
|
|
for sectionIndex := 0 to Pred(Section.section.Count) do
|
|
|
|
if SameText(Section.section[sectionIndex].name, AName) then
|
|
|
|
begin
|
|
|
|
Section.section.Delete(sectionIndex);
|
|
|
|
Break;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
end.
|
|
|
|
|