lazarus/components/codetools/laz_xmlstreaming.pas
mattias bb55ccecbd IDE: started upgrade of xml units
git-svn-id: trunk@25647 -
2010-05-25 20:37:53 +00:00

1164 lines
32 KiB
ObjectPascal

{
This file is part of the Free Component Library
XML serialisation driver
Copyright (c) 2000 by Sebastian Guenther, sg@freepascal.org
See the file COPYING.FPC, included in this distribution,
for details about the copyright.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**********************************************************************}
{
Extended by Mattias Gaertner:
Reading/Writing childs, all kinds of properties,
custom properties (via DefineProperties).
}
unit Laz_XMLStreaming;
{$MODE objfpc}
{$H+}
{$I codetools.inc}
{$DEFINE HasReadWriteBuf}
{$IF defined(VER2_2_0)}
{$UNDEF HasReadWriteBuf}
{$ENDIF}
{$IF (FPC_VERSION = 2) AND (FPC_RELEASE >= 3)}
{$DEFINE USE_NEW_READER_WRITER}
{$IFEND}
interface
uses
SysUtils, Classes, TypInfo, FileProcs,
{$IFDEF NewXMLCfg}
Laz2_DOM, Laz2_XMLWrite
{$ELSE}
Laz_DOM, Laz_XMLWrite
{$ENDIF};
type
TXMLObjectWriterStackElType = (elUnknown, elPropertyList, elChildrenList);
TXMLObjectWriterStackEl = class
public
Element, Parent: TDOMElement;
ElemType: TXMLObjectWriterStackElType;
PropertyName: String;
end;
{ TXMLObjectWriter }
TXMLObjectWriter = class(TAbstractObjectWriter)
private
FDoc: TDOMDocument;
FRootEl: TDOMElement;
FStack: TFPList;
StackEl: TXMLObjectWriterStackEl;
procedure StackPush(const Element: string = '';
ElementType: TXMLObjectWriterStackElType = elUnknown);
procedure StackPop;
function GetPropertyElement(const TypeName: String): TDOMElement;
public
constructor Create(ADoc: TDOMDocument; const APath: string; Append: Boolean);
{ Begin/End markers. Those ones who don't have an end indicator, use
"EndList", after the occurrence named in the comment. Note that this
only counts for "EndList" calls on the same level; each BeginXXX call
increases the current level. }
procedure BeginCollection; override;{ Ends with the next "EndList" }
procedure BeginComponent(Component: TComponent; Flags: TFilerFlags;
ChildPos: Integer); override;{ Ends after the second "EndList" }
procedure BeginList; override;
procedure EndList; override;
procedure BeginProperty(const PropName: String); override;
procedure EndProperty; override;
procedure WriteBinary(const Buffer; Count: Longint); override;
procedure WriteBoolean(Value: Boolean); override;
// procedure WriteChar(Value: Char);
procedure WriteFloat(const Value: Extended); override;
procedure WriteSingle(const Value: Single); override;
procedure WriteCurrency(const Value: Currency); override;
procedure WriteDate(const Value: TDateTime); override;
procedure WriteIdent(const Ident: string); override;
procedure WriteInteger(Value: Int64); override;
procedure WriteMethodName(const Name: String); override;
procedure WriteSet(Value: LongInt; SetType: Pointer); override;
procedure WriteString(const Value: String); override;
procedure WriteWideString(const Value: WideString); override;
{$IFDEF USE_NEW_READER_WRITER}
procedure WriteUInt64(Value: QWord); override;
procedure WriteUnicodeString(const Value: UnicodeString); override;
procedure WriteVariant(const VarValue: Variant); override;
{$ENDIF}
{$IFDEF HasReadWriteBuf}
procedure Write(const Buffer; Count: Longint); override;
{$ENDIF}
public
property Doc: TDOMDocument read FDoc;
end;
TXMLObjectWriterClass = class of TXMLObjectWriter;
{ TXMLObjectReader }
TXMLObjectReader = class(TAbstractObjectReader)
private
FDoc: TDOMDocument;
FElement: TDOMElement;
FElementPosition: integer;
FRootEl: TDOMElement;
function ReadNextValue(Stay: Boolean): TValueType;
public
constructor Create(ADoc: TDOMDocument; const APath: string);
destructor Destroy; override;
function GetRootClassName(out IsInherited: Boolean): string;
{ All ReadXXX methods are called _after_ the value type has been read! }
function NextValue: TValueType; override;
function ReadValue: TValueType; override;
procedure BeginRootComponent; override;
procedure BeginComponent(var Flags: TFilerFlags; var AChildPos: Integer;
var CompClassName, CompName: String); override;
function BeginProperty: String; override;
procedure ReadBinary(const DestData: TMemoryStream); override;
function ReadFloat: Extended; override;
function ReadSingle: Single; override;
function ReadCurrency: Currency; override;
function ReadDate: TDateTime; override;
function ReadIdent(ValueType: TValueType): String; override;
function ReadInt8: ShortInt; override;
function ReadInt16: SmallInt; override;
function ReadInt32: LongInt; override;
function ReadInt64: Int64; override;
function ReadSet(SetType: Pointer): Integer; override;
function ReadStr: String; override;
function ReadString(StringType: TValueType): String; override;
function ReadWideString: WideString; override;
{$IFDEF USE_NEW_READER_WRITER}
function ReadUnicodeString: UnicodeString; override;
{$ENDIF}
procedure SkipComponent(SkipComponentInfos: Boolean); override;
procedure SkipValue; override;
{$IFDEF HasReadWriteBuf}
procedure Read(var Buf; Count: LongInt); override;
{$ENDIF}
public
property Doc: TDOMDocument read FDoc;
property Element: TDOMElement read FElement;// current element node
property ElementPosition: integer read FElementPosition;
end;
TXMLObjectReaderClass = class of TXMLObjectReader;
procedure WriteComponentToXMLStream(AComponent: TComponent; AStream: TStream);
implementation
procedure WriteComponentToXMLStream(AComponent: TComponent; AStream: TStream);
var
Driver: TXMLObjectWriter;
Writer: TWriter;
XMLDocument: TXMLDocument;
begin
XMLDocument:=nil;
Driver:=nil;
Writer:=nil;
try
XMLDocument:=TXMLDocument.Create;
Driver:=TXMLObjectWriter.Create(XMLDocument,'fcl-persistent',true);
Writer:=TWriter.Create(Driver);
Writer.WriteDescendent(AComponent,nil);
WriteXMLFile(XMLDocument,AStream);
finally
Writer.Free;
Driver.Free;
XMLDocument.Free;
end;
end;
procedure TXMLObjectWriter.StackPush(const Element: string;
ElementType: TXMLObjectWriterStackElType);
var
Parent: TDOMElement;
i: Integer;
begin
if Assigned(FStack) then
begin
// append to stack
Parent := StackEl.Element;
if Parent=nil then begin
i:=FStack.Count-1;
while (i>=0) do begin
if (TXMLObjectWriterStackEl(FStack[i]).Element=nil) then
dec(i)
else begin
Parent:=TXMLObjectWriterStackEl(FStack[i]).Element;
break;
end;
end;
if Parent=nil then
Parent:=FRootEl;
end;
FStack.Add(StackEl);
StackEl := TXMLObjectWriterStackEl.Create;
StackEl.Parent := Parent;
end else
begin
// start stack
FStack := TFPList.Create;
StackEl := TXMLObjectWriterStackEl.Create;
StackEl.Parent := FRootEl;
end;
if Element<>'' then begin
// create element
StackEl.Element := FDoc.CreateElement(Element);
StackEl.Parent.AppendChild(StackEl.Element);
StackEl.ElemType:=ElementType;
end;
DebugLn('TXMLObjectWriter.StackPush Element="',Element,'" FStack.Count=',dbgs(FStack.Count),' ',DbgSName(StackEl.Parent));
end;
procedure TXMLObjectWriter.StackPop;
begin
DebugLn('TXMLObjectWriter.StackPop ',dbgs(FStack.Count));
if FStack=nil then
raise Exception.Create('TXMLObjectWriter.StackPop stack empty');
StackEl.Free;
if FStack.Count > 0 then
begin
StackEl := TXMLObjectWriterStackEl(FStack[FStack.Count - 1]);
FStack.Delete(FStack.Count - 1);
end else
begin
FStack.Free;
FStack := nil;
StackEl := nil;
end;
end;
function TXMLObjectWriter.GetPropertyElement(const TypeName: String
): TDOMElement;
var
CustomElement: TDOMElement;
begin
if StackEl.PropertyName<>'' then begin
// normal property
if not Assigned(StackEl.Element) then begin
StackEl.Element := FDoc.CreateElement(TypeName);
StackEl.Parent.AppendChild(StackEl.Element);
StackEl.Element['name'] := StackEl.PropertyName;
Result := StackEl.Element;
end else begin
raise Exception.Create('TXMLObjectWriter.GetPropertyElement property already saved');
end;
end else begin
// custom defined property (via DefineProperties)
CustomElement := FDoc.CreateElement(TypeName);
StackEl.Element.AppendChild(CustomElement);
Result := CustomElement;
end;
end;
constructor TXMLObjectWriter.Create(ADoc: TDOMDocument;
const APath: string; Append: Boolean);
var
Node: TDOMNode;
PathLen: Integer;
StartPos: Integer;
EndPos: LongInt;
NodeName: string;
Child: TDOMNode;
ParentNode: TDOMNode;
begin
inherited Create;
FDoc := ADoc;
Node := Doc.DocumentElement;
PathLen:=length(APath);
StartPos:=1;
while True do begin
EndPos:=StartPos;
while (EndPos<=PathLen) and (APath[EndPos]<>'/') do inc(EndPos);
if EndPos>StartPos then begin
SetLength(NodeName,EndPos-StartPos);
Move(APath[StartPos],NodeName[1],EndPos-StartPos);
StartPos:=EndPos+1;
Child := Node.FindNode(NodeName);
if not Assigned(Child) then
begin
Child := Doc.CreateElement(NodeName);
Node.AppendChild(Child);
end;
Node := Child;
end else if EndPos>PathLen then begin
break;
end else begin
StartPos:=EndPos+1;
end;
end;
if Node is TDOMElement then
FRootEl:=TDOMElement(Node)
else
FRootEl:=nil;
NodeName:='fcl-persistent';
ParentNode:=nil;
if (not Append) and (FRootEl<>nil) then begin
NodeName:=FRootEl.NodeName;
ParentNode:=FRootEl.ParentNode;
if ParentNode<>nil then
ParentNode.RemoveChild(FRootEl)
else
FRootEl.Free;
FRootEl:=nil;
end;
if FRootEl=nil then
FRootEl := FDoc.CreateElement(NodeName);
if ParentNode=nil then
FDoc.AppendChild(FRootEl)
else
ParentNode.AppendChild(FRootEl);
end;
procedure TXMLObjectWriter.BeginCollection;
begin
GetPropertyElement('collectionproperty');
StackPush('collection');
end;
procedure TXMLObjectWriter.BeginComponent(Component: TComponent; Flags: TFilerFlags;
ChildPos: Integer);
// TWriter expects to push two elements on the stack, which are popped by
// two EndList calls.
begin
StackPush('component');
if Length(Component.Name) > 0 then
StackEl.Element['name'] := Component.Name;
StackEl.Element['class'] := Component.ClassName;
StackPush('properties',elPropertyList);
end;
procedure TXMLObjectWriter.BeginList;
begin
StackPush('list');
end;
procedure TXMLObjectWriter.EndList;
begin
if StackEl.ElemType = elPropertyList then
begin
// end the property list and start the children list
if not StackEl.Element.HasChildNodes then
StackEl.Parent.RemoveChild(StackEl.Element);
StackPop;
StackPush('children',elChildrenList);
end else if StackEl.ElemType = elChildrenList then
begin
// end the children list and the component
if not StackEl.Element.HasChildNodes then
StackEl.Parent.RemoveChild(StackEl.Element);
StackPop; // end children
StackPop; // end component
end else
StackPop;
end;
procedure TXMLObjectWriter.BeginProperty(const PropName: String);
begin
//DebugLn('TXMLObjectWriter.BeginProperty "',PropName,'"');
StackPush;
StackEl.PropertyName := PropName;
end;
procedure TXMLObjectWriter.EndProperty;
begin
StackPop;
end;
procedure TXMLObjectWriter.WriteBinary(const Buffer; Count: Longint);
var
s: string;
begin
SetLength(s,Count);
if s<>'' then
System.Move(Buffer,s[1],length(s));
GetPropertyElement('binary')['value'] := s;
end;
procedure TXMLObjectWriter.WriteBoolean(Value: Boolean);
begin
if Value then
GetPropertyElement('boolean')['value'] := 'true'
else
GetPropertyElement('boolean')['value'] := 'false';
end;
procedure TXMLObjectWriter.WriteFloat(const Value: Extended);
begin
GetPropertyElement('extended')['value'] := FloatToStr(Value);
end;
procedure TXMLObjectWriter.WriteSingle(const Value: Single);
begin
GetPropertyElement('single')['value'] := FloatToStr(Value);
end;
procedure TXMLObjectWriter.WriteCurrency(const Value: Currency);
begin
GetPropertyElement('Currency')['value'] := FloatToStr(Value);
end;
procedure TXMLObjectWriter.WriteDate(const Value: TDateTime);
begin
GetPropertyElement('date')['value'] := FloatToStr(Value);
end;
procedure TXMLObjectWriter.WriteIdent(const Ident: string);
begin
GetPropertyElement('ident')['value'] := Ident;
end;
procedure TXMLObjectWriter.WriteInteger(Value: Int64);
begin
GetPropertyElement('integer')['value'] := IntToStr(Value);
end;
procedure TXMLObjectWriter.WriteMethodName(const Name: String);
begin
GetPropertyElement('method')['value'] := Name;
end;
procedure TXMLObjectWriter.WriteSet(Value: LongInt; SetType: Pointer);
var
i: Integer;
Mask: LongInt;
s: String;
begin
Mask := 1;
s:='';
for i := 0 to 31 do begin
if (Value and Mask) <> 0 then begin
if s<>'' then s:=s+',';
s:=s+GetEnumName(PTypeInfo(SetType), i);
end;
Mask := Mask shl 1;
end;
GetPropertyElement('set')['value'] := s;
end;
procedure TXMLObjectWriter.WriteString(const Value: String);
begin
GetPropertyElement('string')['value'] := Value;
end;
procedure TXMLObjectWriter.WriteWideString(const Value: WideString);
// save widestrings as utf8
begin
GetPropertyElement('widestring')['value'] := System.UTF8Encode(Value);
end;
{$IFDEF USE_NEW_READER_WRITER}
procedure TXMLObjectWriter.WriteUInt64(Value: QWord);
begin
GetPropertyElement('uint64')['value'] := IntToStr(Value);
end;
procedure TXMLObjectWriter.WriteUnicodeString(const Value: UnicodeString);
// save unicodestrings as utf8
begin
GetPropertyElement('unicodestring')['value'] := System.UTF8Encode(Value);
end;
procedure TXMLObjectWriter.WriteVariant(const VarValue: Variant);
begin
case tvardata(VarValue).vtype of
varEmpty:
begin
GetPropertyElement('uint64')['value'] := 'nil';
end;
varNull:
begin
GetPropertyElement('uint64')['value'] := 'null';
end;
{ all integer sizes must be split for big endian systems }
varShortInt,varSmallInt,varInteger,varInt64:
begin
WriteInteger(VarValue);
end;
varQWord:
begin
WriteUInt64(VarValue);
end;
varBoolean:
begin
WriteBoolean(VarValue);
end;
varCurrency:
begin
WriteCurrency(VarValue);
end;
varSingle:
begin
WriteSingle(VarValue);
end;
varDouble:
begin
WriteFloat(VarValue);
end;
varDate:
begin
WriteDate(VarValue);
end;
varOleStr,varString:
begin
WriteWideString(VarValue);
end;
else
raise EWriteError.CreateFmt('Unsupported property variant type %d', [Ord(tvardata(VarValue).vtype)]);
end;
end;
{$ENDIF}
{$IFDEF HasReadWriteBuf}
procedure TXMLObjectWriter.Write(const Buffer; Count: Longint);
begin
// there can be arbitrary lots of Write calls
raise Exception.Create('TODO: TXMLObjectWriter.Write');
end;
{$ENDIF}
{ TXMLObjectReader }
function TXMLObjectReader.ReadNextValue(Stay: Boolean): TValueType;
procedure RaiseUnknownNode(Node: TDOMNode);
begin
raise EReadError.Create('TXMLObjectReader: unknown node "'+Node.NodeName+'"');
end;
procedure RaiseUnknownParentNode(Node: TDOMNode);
begin
raise EReadError.Create('TXMLObjectReader: unknown parent node "'+Node.NodeName+'" Element="'+FElement.NodeName+'"');
end;
procedure RaiseInvalidElementPosition;
begin
raise EReadError.Create('TXMLObjectReader: invalid ElementPosition='+IntToStr(FElementPosition)+' Node='+FElement.NodeName);
end;
procedure RaiseNodeNotFound(const NodeName: string);
begin
raise EReadError.Create('TXMLObjectReader: expected "'+NodeName+'", but found "'+FElement.NodeName+'"');
end;
procedure CheckNode(const NodeName: string);
begin
if FElement.NodeName<>NodeName then
RaiseNodeNotFound(NodeName);
end;
procedure GoToNextComponent;
begin
FElement:=FElement.ParentNode as TDOMElement;
CheckNode('component');
FElementPosition:=0;
if FElement.NextSibling is TDOMElement then begin
// go to next component
//writeln('TXMLObjectReader.ReadNextValue properties: next component');
FElement:=TDOMElement(FElement.NextSibling);
CheckNode('component');
end else begin
// end of children list
if FElement.ParentNode.NodeName='children' then begin
//writeln('TXMLObjectReader.ReadNextValue end of children list');
FElement:=FElement.ParentNode as TDOMElement;
FElementPosition:=1;
end else begin
//writeln('TXMLObjectReader.ReadNextValue END reading');
FElement:=nil;
end;
end;
end;
var
CurValue: String;
CurInt64: Int64;
begin
//writeln('TXMLObjectReader.ReadNextValue Stay=',Stay,' Element=',FElement.NodeName,' Pos=',FElementPosition);
if FElement.NodeName='component' then begin
//writeln('TXMLObjectReader.ReadNextValue is start of component');
Result:=vaString;
if not Stay then begin
// here a BeginComponent shoud be called, not ReadValue
RaiseUnknownNode(FElement);
end;
end
else if FElement.NodeName='properties' then begin
// FElement is at end of property list or non existing children list
// 0: end of property list
// 1: end of non existing children list
//writeln('TXMLObjectReader.ReadNextValue FElement is at end of property list');
Result:=vaNull;
if not Stay then begin
if FElement.NextSibling is TDOMElement then begin
// leave properties and go to first child component
//writeln('TXMLObjectReader.ReadNextValue properties: children');
FElement:=TDOMElement(FElement.NextSibling);
FElementPosition:=0;
CheckNode('children');
if not (FElement.FirstChild is TDOMElement) then
RaiseUnknownNode(FElement);
FElement:=TDOMElement(FElement.FirstChild);
end else begin
// there is no children list behind the properties -> simulate it
if FElementPosition=0 then begin
inc(FElementPosition);
end else begin
// children has been simulated -> now go to next component
GoToNextComponent;
end;
end;
end;
end
else if FElement.NodeName='children' then begin
// end of children list
//writeln('TXMLObjectReader.ReadNextValue End of children list');
Result:=vaNull;
if not Stay then begin
GoToNextComponent;
end;
end
else if FElement.NodeName='list' then begin
// FElement is a list element
// It has 2 positions:
// 0: vaList
// 1: end of list
case FElementPosition of
0:begin
//writeln('TXMLObjectReader.ReadNextValue list: vaList');
Result:=vaList;
if (FElement.FirstChild is TDOMElement) then begin
// the list has childs
if not Stay then begin
FElement:=TDOMElement(FElement.FirstChild);
FElementPosition:=0;
end;
end else begin
// empty list
if not Stay then
inc(FElementPosition);
end;
end;
1:begin
// end of list
Result:=vaNull;
if not Stay then begin
if (FElement.NextSibling is TDOMElement) then begin
//writeln('TXMLObjectReader.ReadNextValue list: end of childs, next list');
FElement:=TDOMElement(FElement.NextSibling);
FElementPosition:=0;
end else begin
//writeln('TXMLObjectReader.ReadNextValue list: end of childs, end of collection');
FElement:=FElement.ParentNode as TDOMElement;
FElementPosition:=0;
end;
end;
end;
end;
end
else if FElement.NodeName='collection' then begin
// FElement is at end of collection
//writeln('TXMLObjectReader.ReadNextValue FElement is at end of collection');
Result:=vaNull;
end
else if (FElement.ParentNode.NodeName='properties')
or (FElement.ParentNode.NodeName='list') then begin
// FElement is a property
// It has 3 positions:
// 0: name
// 1: value type
// 2: value
case FElementPosition of
0:// the property name
begin
Result:=vaString;
if not Stay then
inc(FElementPosition);
end;
1:// value type
begin
if FElement.NodeName='integer' then begin
CurValue:=FElement['value'];
CurInt64:=StrToInt64(CurValue);
if (CurInt64 >= -128) and (CurInt64 <= 127) then begin
Result:=vaInt8
end else if (CurInt64 >= -32768) and (CurInt64 <= 32767) then begin
Result:=vaInt16;
end else if (CurInt64 >= Low(Integer)) and (CurInt64 <= High(integer))
then begin
Result:=vaInt32;
end else
Result:=vaInt64;
end else if FElement.NodeName='string' then begin
CurValue:=FElement['value'];
if length(CurValue)<=255 then
Result:=vaString
else
Result:=vaLString;
end else if FElement.NodeName='ident' then
Result:=vaIdent
else if FElement.NodeName='boolean' then begin
if FElement['value']='true' then
Result:=vaTrue
else
Result:=vaFalse;
end else if FElement.NodeName='method' then
Result:=vaIdent
else if FElement.NodeName='set' then
Result:=vaSet
else if FElement.NodeName='extended' then
Result:=vaExtended
else if FElement.NodeName='widestring' then
Result:=vaWString
{$IFDEF USE_NEW_READER_WRITER}
else if FElement.NodeName = 'uint64' then
Result:=vaQWord
else if FElement.NodeName='unicodestring' then
Result:=vaUString
else if FElement.NodeName='variant' then
begin
if FElement['value'] = 'nil' then
Result := vaNil
else
Result := vaNull;
end
{$ENDIF}
else if FElement.NodeName='collectionproperty' then
Result:=vaCollection
else
RaiseUnknownNode(FElement);
if not Stay then begin
inc(FElementPosition);
case Result of
vaTrue, vaFalse: ReadValue;
vaCollection:
begin
// go to node 'collection'
FElement:=FElement.FirstChild as TDOMElement;
CheckNode('collection');
FElementPosition:=0;
// go to node 'list'
if Assigned(FElement.FirstChild) and (FElement.FirstChild.NodeName='list') then
FElement:=FElement.FirstChild as TDOMElement;
end;
end;
end;
end;
2:// value
begin
if FElement.NextSibling<>nil then begin
Result:=vaString;
if not Stay then begin
FElement:=FElement.NextSibling as TDOMElement;
FElementPosition:=0;
end;
end else begin
// end of property list
Result:=vaNull;
if not Stay then begin
FElement:=FElement.ParentNode as TDOMElement;
FElementPosition:=0;
if FElement.NodeName='list' then
FElementPosition:=1;
end;
end;
end;
else
RaiseInvalidElementPosition;
end;
end else begin
RaiseUnknownParentNode(FElement.ParentNode);
end;
//writeln('TXMLObjectReader.ReadNextValue Result=',GetEnumName(TypeInfo(TValueType),ord(Result)));
end;
constructor TXMLObjectReader.Create(ADoc: TDOMDocument; const APath: string);
var
Node: TDOMNode;
PathLen: Integer;
StartPos: Integer;
EndPos: LongInt;
NodeName: string;
Child: TDOMNode;
procedure RaiseMissingNode;
begin
raise Exception.Create('XML node not found '+APath);
end;
procedure RaiseNotDOMElement;
begin
raise Exception.Create('invalid XML node '+APath);
end;
begin
inherited Create;
FDoc := ADoc;
Node := Doc.DocumentElement;
PathLen:=length(APath);
StartPos:=1;
while True do begin
EndPos:=StartPos;
while (EndPos<=PathLen) and (APath[EndPos]<>'/') do inc(EndPos);
if EndPos>StartPos then begin
SetLength(NodeName,EndPos-StartPos);
Move(APath[StartPos],NodeName[1],EndPos-StartPos);
StartPos:=EndPos+1;
Child := Node.FindNode(NodeName);
if not Assigned(Child) then
RaiseMissingNode;
Node := Child;
end else if EndPos>PathLen then begin
break;
end else begin
StartPos:=EndPos+1;
end;
end;
if not (Node is TDOMElement) then
RaiseNotDOMElement;
FRootEl:=TDOMElement(Node);
FElement:=FRootEl;
FElementPosition:=0;
end;
destructor TXMLObjectReader.Destroy;
begin
inherited Destroy;
end;
function TXMLObjectReader.GetRootClassName(out IsInherited: Boolean): string;
var
ComponentNode: TDOMNode;
CompElement: TDOMElement;
begin
IsInherited:=false;
ComponentNode:=FRootEl.FindNode('component');
if ComponentNode=nil then
raise Exception.Create('component node not found');
if not (ComponentNode is TDOMElement) then
raise Exception.Create('component node is not a dom element');
CompElement:=TDOMElement(ComponentNode);
Result:=CompElement['class'];
DebugLn('TXMLObjectReader.GetRootClassName RootClassName="',Result,'"');
// TODO: IsInherited
end;
function TXMLObjectReader.NextValue: TValueType;
begin
Result:=ReadNextValue(true);
end;
function TXMLObjectReader.ReadValue: TValueType;
begin
Result:=ReadNextValue(false);
end;
procedure TXMLObjectReader.BeginRootComponent;
procedure RaiseComponentNodeNotFound;
begin
raise Exception.Create('component node not found');
end;
var
Node: TDOMNode;
begin
//writeln('TXMLObjectReader.BeginRootComponent ');
Node:=FElement.FindNode('component');
if Node=nil then
RaiseComponentNodeNotFound;
end;
procedure TXMLObjectReader.BeginComponent(var Flags: TFilerFlags;
var AChildPos: Integer; var CompClassName, CompName: String);
var
ComponentNode: TDOMNode;
PropertiesNode: TDOMNode;
begin
//writeln('TXMLObjectReader.BeginComponent START');
if FElement.NodeName='component' then
ComponentNode:=FElement
else
ComponentNode:=FElement.FindNode('component');
if ComponentNode=nil then
raise Exception.Create('component node not found');
if not (ComponentNode is TDOMElement) then
raise Exception.Create('component node is not a dom element');
FElement:=TDOMElement(ComponentNode);
CompName:=FElement['name'];
CompClassName:=FElement['class'];
DebugLn('TXMLObjectReader.BeginComponent CompName="',CompName,'" CompClassName="',CompClassName,'"');
PropertiesNode:=FElement.FindNode('properties');
if PropertiesNode=nil then
raise Exception.Create('properties node not found');
if not (PropertiesNode is TDOMElement) then
raise Exception.Create('properties node is not a dom element');
// if there are properties, then set FElement to the first property
FElement:=TDOMElement(PropertiesNode);
if FElement.FirstChild is TDOMElement then
FElement:=TDOMElement(FElement.FirstChild);
FElementPosition:=0;
end;
function TXMLObjectReader.BeginProperty: String;
begin
Result:=FElement['name'];
//writeln('TXMLObjectReader.BeginProperty Result="',Result,'"');
inc(FElementPosition);
end;
procedure TXMLObjectReader.ReadBinary(const DestData: TMemoryStream);
var
Value: String;
begin
Value:=FElement['value'];
if Value<>'' then
DestData.Write(Value[1],length(Value));
ReadValue;
//writeln('TXMLObjectReader.ReadBinary ');
end;
function TXMLObjectReader.ReadFloat: Extended;
var
Value: String;
begin
Result:=0;
Value:=FElement['value'];
Result:=StrToFloat(Value);
ReadValue;
//writeln('TXMLObjectReader.ReadFloat ',Result);
end;
function TXMLObjectReader.ReadSingle: Single;
var
Value: String;
FloatError: integer;
Back: single;
begin
Result:=0;
Value:=FElement['value'];
Val(Value, Back, FloatError);
if FloatError=0 then ;
Result:=Back;
ReadValue;
//writeln('TXMLObjectReader.ReadSingle ',Result);
end;
function TXMLObjectReader.ReadCurrency: Currency;
var
Value: String;
begin
Result:=0;
Value:=FElement['value'];
Result:=StrToFloat(Value);
ReadValue;
//writeln('TXMLObjectReader.ReadCurrency ',Result);
end;
function TXMLObjectReader.ReadDate: TDateTime;
var
Value: String;
begin
Result:=0;
Value:=FElement['value'];
Result:=StrToFloat(Value);
ReadValue;
//writeln('TXMLObjectReader.ReadDate ',Result);
end;
function TXMLObjectReader.ReadIdent(ValueType: TValueType): String;
begin
Result:=FElement['value'];
ReadValue;
//writeln('TXMLObjectReader.ReadIdent ',Result);
end;
function TXMLObjectReader.ReadInt8: ShortInt;
var
Value: String;
FloatError: integer;
Back: ShortInt;
begin
Result:=0;
Value:=FElement['value'];
Val(Value, Back, FloatError);
if FloatError=0 then ;
Result:=Back;
ReadValue;
//writeln('TXMLObjectReader.ReadInt8 ',Result);
end;
function TXMLObjectReader.ReadInt16: SmallInt;
var
Value: String;
FloatError: integer;
Back: SmallInt;
begin
Result:=0;
Value:=FElement['value'];
Val(Value, Back, FloatError);
if FloatError=0 then ;
Result:=Back;
ReadValue;
//writeln('TXMLObjectReader.ReadInt16 ',Result);
end;
function TXMLObjectReader.ReadInt32: LongInt;
var
Value: String;
FloatError: integer;
Back: Longint;
begin
Result:=0;
Value:=FElement['value'];
Val(Value, Back, FloatError);
if FloatError=0 then ;
Result:=Back;
ReadValue;
//writeln('TXMLObjectReader.ReadInt32 ',Result);
end;
function TXMLObjectReader.ReadInt64: Int64;
var
Value: String;
FloatError: integer;
Back: Int64;
begin
Result:=0;
Value:=FElement['value'];
Val(Value, Back, FloatError);
if FloatError=0 then ;
Result:=Back;
ReadValue;
//writeln('TXMLObjectReader.ReadInt64 ',Result);
end;
function TXMLObjectReader.ReadSet(SetType: Pointer): Integer;
var
s: String;
StartPos: Integer;
EndPos: LongInt;
Name: String;
i: LongInt;
begin
Result:=0;
s:=FElement['value'];
StartPos:=1;
while (StartPos<=length(s)) do begin
EndPos:=StartPos;
while (EndPos<=length(s)) and (s[EndPos]<>',') do inc(EndPos);
if EndPos>StartPos then begin
Name:=copy(s,StartPos,EndPos-StartPos);
i:=GetEnumValue(PTypeInfo(SetType),Name);
Result:=Result or (1 shl i);
end;
StartPos:=EndPos+1;
end;
ReadValue;
//writeln('TXMLObjectReader.ReadSet ',HexStr(Cardinal(Result),8));
end;
function TXMLObjectReader.ReadStr: String;
begin
Result:=FElement['value'];
ReadValue;
//writeln('TXMLObjectReader.ReadStr "',Result,'"');
end;
function TXMLObjectReader.ReadString(StringType: TValueType): String;
begin
Result:=FElement['value'];
if (StringType=vaString) and (length(Result)>255) then
raise Exception.Create('TXMLObjectReader.ReadString invalid StringType');
ReadValue;
//writeln('TXMLObjectReader.ReadString "',Result,'"');
end;
function TXMLObjectReader.ReadWideString: WideString;
var
ValueAsUTF8: String;
begin
ValueAsUTF8:=FElement['value'];
Result:=System.UTF8Decode(ValueAsUTF8);
ReadValue;
//writeln('TXMLObjectReader.ReadWideString "',ValueAsUTF8,'"');
end;
{$IFDEF USE_NEW_READER_WRITER}
function TXMLObjectReader.ReadUnicodeString: UnicodeString;
var
ValueAsUTF8: String;
begin
ValueAsUTF8:=FElement['value'];
Result:=System.UTF8Decode(ValueAsUTF8);
ReadValue;
end;
{$ENDIF}
procedure TXMLObjectReader.SkipComponent(SkipComponentInfos: Boolean);
var
NextNode: TDOMNode;
begin
NextNode:=FElement.NextSibling;
if (NextNode=nil) or (NextNode is TDOMElement) then
FElement:=TDOMElement(NextNode);
//writeln('TXMLObjectReader.SkipComponent ');
end;
procedure TXMLObjectReader.SkipValue;
begin
ReadValue;
//writeln('TXMLObjectReader.SkipValue ');
end;
{$IFDEF HasReadWriteBuf}
procedure TXMLObjectReader.Read(var Buf; Count: LongInt);
begin
raise Exception.Create('TODO: TXMLObjectReader.Read');
//writeln('TXMLObjectReader.Read ');
end;
{$ENDIF}
end.