home *** CD-ROM | disk | FTP | other *** search
- unit XmlClasses;
-
- interface
-
- uses Classes, SysUtils, MSXML_TLB, Dialogs, ComCtrls, ImgList, Graphics;
-
- type
- TXmlNodeType = (xntDocument, xntElement, xntDocumentFragment,
- xntText, xntComment, xntCDATASection);
-
- TCharEntity = (ceLt, ceGt, ceQuot, ceApos, ceAmp);
-
- TCharEntities = set of TCharEntity;
-
- TSubstituteCharEntitiesEvent = procedure(Sender: TObject;
- var Text: String; var SkipTranslation: Boolean) of Object;
-
- const
- XmlNodeNames: array[xntDocument..xntCDATASection] of String =
- ('#document', '', '#document-fragment', '#text',
- '#comment', '#cdata-section');
-
- type
- EXmlDError = class(Exception);
-
- EXmlDParseError = class(Exception)
- FErrorCode: Integer;
- FReason: String;
- FSrcText: String;
- FLine: Integer;
- FLinePos: Integer;
- public
- constructor Create(ParseError: IXMLDOMParseError);
- procedure ShowParseError;
- property ErrorCode: Integer read FErrorCode;
- property Reason: String read FReason;
- property SrcText: String read FSrcText;
- property Line: Integer read FLine;
- property LinePos: Integer read FLinePos;
- end;
-
- TXmlName = String;
-
- TXmlDDocument = class;
- TXmlDStructureNode = class;
- TXmlDElement = class;
- TXmlDDocumentFragment = class;
- TXmlDCDATASection = class;
- TXmlDComment = class;
- TXmlDText = class;
- TXmlDAttrList = class;
- TXmlDElementIterator = class;
- TXmlDElementPattern = class;
-
- TXmlDNode = class(TPersistent)
- private
- FPreviousSibling: TXmlDNode;
- FNextSibling: TXmlDNode;
- FParentNode: TXmlDStructureNode;
- FNodeType: TXmlNodeType;
- FTag: Integer;
- FLevel: Integer;
- protected
- function GetFirstChild: TXmlDNode; virtual;
- function GetLastChild: TXmlDNode; virtual;
- function GetOwnerDocument: TXmlDDocument;
- function GetNodeName: TXmlName; virtual;
- function GetNodeValue: String; virtual;
- procedure SetLevel(Lvl: Integer);
- procedure SetNodeName(const Value: TXmlName); virtual;
- procedure SetNodeValue(const Value: String); virtual;
- procedure SetParent(ParentNode: TXmlDStructureNode);
- procedure WriteToStream(Stream: TStream;
- FormattedForPrint: Boolean); virtual; abstract;
- procedure WriteFormattedPrefix(Stream: TStream);
- procedure WriteFormattedSuffix(Stream: TStream);
- public
- constructor Create;
- function CloneNode(RecurseChildren: Boolean = False): TXmlDNode;
- virtual; abstract;
- procedure AppendChild(NewNode: TXmlDNode); virtual;
- function ReplaceChild(NewNode: TXmlDNode; OldNode: TXmlDNode):
- TXmlDNode; virtual;
- procedure InsertBefore(NewNode: TXmlDNode; ThisNode: TXmlDNode);
- virtual;
- function RemoveChild(ThisNode: TXmlDNode): TXmlDNode; virtual;
- function HasChildNodes: Boolean; virtual;
- procedure ZeroAllTags;
- property FirstChild: TXmlDNode read GetFirstChild;
- property LastChild: TXmlDNode read GetLastChild;
- property PreviousSibling: TXmlDNode read FPreviousSibling;
- property NextSibling: TXmlDNode read FNextSibling;
- property ParentNode: TXmlDStructureNode read FParentNode;
- property OwnerDocument: TXmlDDocument read GetOwnerDocument;
- property NodeName: TXmlName read GetNodeName write SetNodeName;
- property NodeType: TXmlNodeType read FNodeType;
- property NodeValue: String read GetNodeValue write SetNodeValue;
- property Level: Integer read FLevel;
- property Tag: Integer read FTag write FTag;
- end;
-
- TXmlDStructureNode = class(TXmlDNode)
- private
- FAttrList: TXmlDAttrList;
- FFirstChild: TXmlDNode;
- FLastChild: TXmlDNode;
- FElementCount: Integer;
- protected
- procedure AppendDocFragChild(NewNode: TXmlDDocumentFragment);
- procedure AssignAttrNodesToTreeNodes(ParXmlNode: TXmlDNode;
- ParTreeNode: TTreeNode);
- procedure AssignNodeToTreeNode(XmlNode: TXmlDNode;
- TreeNode: TTreeNode);
- procedure CloneChildren(FromNode: TXmlDStructureNode);
- function GetElementByName(const Name: String): TXmlDElement;
- function GetElements(Index: Integer): TXmlDElement;
- procedure InsertDocFragBefore(NewNode: TXmlDDocumentFragment;
- ThisNode: TXmlDNode);
- procedure WriteChildrenToStream(Stream: TStream;
- FormattedForPrint:Boolean);
- public
- constructor Create;
- destructor Destroy; override;
- procedure AssignTo(Dest: TPersistent); override;
- function GetFirstChild: TXmlDNode; override;
- function GetLastChild: TXmlDNode; override;
- procedure AppendChild(NewNode: TXmlDNode); override;
- procedure InsertBefore(NewNode: TXmlDNode; ThisNode: TXmlDNode);
- override;
- function ReplaceChild(NewNode: TXmlDNode; OldNode: TXmlDNode):
- TXmlDNode; override;
- function RemoveChild(ThisNode: TXmlDNode): TXmlDNode; override;
- function HasChildNodes: Boolean; override;
- function GetFirstChildElement: TXmlDElement;
- property AttrList: TXmlDAttrList read FAttrList;
- property ElementCount: Integer read FElementCount;
- property Elements[Index: Integer]: TXmlDElement read GetElements;
- property ElementByName[const Name: String]: TXmlDElement
- read GetElementByName; default;
- end;
-
- TXmlDContentNode = class(TXmlDNode)
- private
- FValue: String;
- protected
- function GetNodeValue: String; override;
- procedure SetNodeValue(const Value: String); override;
- end;
-
- TXmlDDocument = class(TXmlDStructureNode)
- private
- FDocumentElement: TXmlDElement;
- FDocumentTypeDefinition: String;
- FAttrCharEntities: TCharEntities;
- FTextCharEntities: TCharEntities;
- FOnOutputAttrValue: TSubstituteCharEntitiesEvent;
- FOnOutputTextValue: TSubstituteCharEntitiesEvent;
- DiscardUnsupportedItems: Boolean;
- protected
- procedure WriteToStream(Stream: TStream;
- FormattedForPrint: Boolean); override;
- procedure WritePrologToStream(Stream: TStream);
- procedure DecodePrologAttrs(S: String);
- procedure LoadFromDOMDocument(Doc: IXMLDOMDocument);
- procedure LoadChildNodes(ParNode: TXmlDNode;
- ParDOMNode: IXMLDOMNode);
- procedure LoadAttributes(Node: TXmlDElement;
- DOMNode: IXMLDOMNode);
- public
- constructor Create;
- function CloneNode(RecurseChildren: Boolean = False): TXmlDNode;
- override;
- procedure Clear;
- procedure AppendChild(NewNode: TXmlDNode); override;
- function ReplaceChild(NewNode: TXmlDNode; OldNode: TXmlDNode):
- TXmlDNode; override;
- procedure InsertBefore(NewNode: TXmlDNode; ThisNode: TXmlDNode);
- override;
- function RemoveChild(ThisNode: TXmlDNode): TXmlDNode; override;
- function CreateCDATASection(const Text: String):
- TXmlDCDATASection;
- function CreateComment(const Text: String): TXmlDComment;
- function CreateDocumentFragment: TXmlDDocumentFragment;
- function CreateElement(const TagName: TXmlName): TXmlDElement;
- overload;
- function CreateElement(const TagName: TXmlName;
- const Data: String): TXmlDElement; overload;
- function CreateElement(const TagName: TXmlName;
- const Data: String; const AttrName: TXmlName;
- const AttrValue: String): TXmlDElement; overload;
- function CreateElement(const TagName: TXmlName;
- const Data: String; const AttrNames: array of TXmlName;
- const AttrValues: array of String): TXmlDElement; overload;
- function CreateTextNode(const Text: String): TXmlDText;
- procedure LoadFromStream(Stream: TStream;
- ValidateOnParse: Boolean = True;
- DiscardUnsupportedItems: Boolean = False);
- procedure LoadFromFile(const FileName: String;
- ValidateOnParse: Boolean = True;
- DiscardUnsupportedItems: Boolean = False);
- procedure SaveToStream(Stream: TStream;
- FormattedForPrint: Boolean = False);
- procedure SaveToFile(const FileName: String;
- FormattedForPrint: Boolean = False);
- property DocumentElement: TXmlDElement read FDocumentElement;
- property DocumentTypeDefinition: String
- read FDocumentTypeDefinition write FDocumentTypeDefinition;
- property AttrCharEntities: TCharEntities read FAttrCharEntities
- write FAttrCharEntities;
- property TextCharEntities: TCharEntities read FTextCharEntities
- write FTextCharEntities;
- property OnOutputAttrValue: TSubstituteCharEntitiesEvent
- read FOnOutputAttrValue write FOnOutputAttrValue;
- property OnOutputTextValue: TSubstituteCharEntitiesEvent
- read FOnOutputTextValue write FOnOutputTextValue;
- end;
-
- TXmlDElement = class(TXmlDStructureNode)
- private
- FNodeName: TXmlName;
- protected
- function GetNodeName: TXmlName; override;
- function GetAsBoolean: Boolean;
- function GetAsCurrency: Currency;
- function GetAsDate: TDateTime;
- function GetAsDateTime: TDateTime;
- function GetAsInteger: Integer;
- function GetAsString: String;
- function GetAsTime: TDateTime;
- function GetFirstTextNodeValue: String;
- procedure SetAsBoolean(const Value: Boolean);
- procedure SetAsCurrency(const Value: Currency);
- procedure SetAsDate(const Value: TDateTime);
- procedure SetAsDateTime(const Value: TDateTime);
- procedure SetAsInteger(const Value: Integer);
- procedure SetAsString(const Value: String);
- procedure SetAsTime(const Value: TDateTime);
- procedure SetNodeName(const Value: TXmlName); override;
- procedure SetFirstTextNodeValue(const Value: String);
- procedure WriteToStream(Stream: TStream;
- FormattedForPrint: Boolean); override;
- public
- constructor Create;
- function CloneNode(RecurseChildren: Boolean = False): TXmlDNode;
- override;
- function GetNextSiblingElement: TXmlDElement;
- property AsBoolean: Boolean read GetAsBoolean write SetAsBoolean;
- property AsCurrency: Currency read GetAsCurrency
- write SetAsCurrency;
- property AsDate: TDateTime read GetAsDate write SetAsDate;
- property AsDateTime: TDateTime read GetAsDateTime
- write SetAsDateTime;
- property AsInteger: Integer read GetAsInteger write SetAsInteger;
- property AsTime: TDateTime read GetAsTime write SetAsTime;
- property AsString: String read GetAsString write SetAsString;
- end;
-
- TXmlDDocumentFragment = class(TXmlDStructureNode)
- protected
- procedure WriteToStream(Stream: TStream;
- FormattedForPrint: Boolean); override;
- public
- constructor Create;
- function CloneNode(RecurseChildren: Boolean = False): TXmlDNode;
- override;
- end;
-
- TXmlDText = class(TXmlDContentNode)
- protected
- procedure WriteToStream(Stream: TStream;
- FormattedForPrint: Boolean); override;
- public
- constructor Create;
- function CloneNode(RecurseChildren: Boolean): TXmlDNode; override;
- end;
-
- TXmlDComment = class(TXmlDContentNode)
- protected
- procedure WriteToStream(Stream: TStream;
- FormattedForPrint: Boolean); override;
- public
- constructor Create;
- function CloneNode(RecurseChildren: Boolean): TXmlDNode; override;
- end;
-
- TXmlDCDATASection = class(TXmlDContentNode)
- protected
- procedure WriteToStream(Stream: TStream;
- FormattedForPrint: Boolean); override;
- public
- constructor Create;
- function CloneNode(RecurseChildren: Boolean): TXmlDNode; override;
- end;
-
- TXmlDAttrList = class(TPersistent)
- private
- List: TStringList;
- FOwnerNode: TXmlDStructureNode;
- protected
- function Add(const S: String): Integer;
- function GetCount: Integer;
- function GetValues(const Name: TXmlName): String;
- function GetNames(Index: Integer): TXmlName;
- procedure SetValues(const Name: TXmlName; const Value: String);
- procedure WriteToStream(Stream: TStream);
- public
- constructor Create;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- procedure Clear;
- property Count: Integer read GetCount;
- property OwnerNode: TXmlDStructureNode read FOwnerNode;
- property Names[Index: Integer]: TXmlName read GetNames;
- property Values[const Name: TXmlName]: String read GetValues
- write SetValues; default;
- end;
-
- TXmlDElementIterator = class(TObject)
- private
- CurrNode: TXmlDStructureNode;
- RootNode: TXmlDStructurenode;
- Position: TList;
- ElementPattern: TXmlDElementPattern;
- protected
- function NextElementInPattern: TXmlDElement;
- function NextElementInStructure: TXmlDElement;
- public
- constructor Create(ContextNode: TXmlDStructureNode = nil;
- const Pattern: String = '');
- destructor Destroy; override;
- function Next: TXmlDElement;
- procedure Reset(ContextNode: TXmlDStructureNode = nil;
- const Pattern: String = '');
- end;
-
- TElementPatternMatch = (epmNoMatch, epmPathMatch, epmEndMatch);
-
- TXmlDElementPattern = class(TObject)
- private
- RootNode: TXmlDStructureNode;
- PatternPieces: TStringList;
- PatternLevels: Integer;
- protected
- procedure ParsePattern(const Pattern: String);
- public
- constructor Create(ContextNode: TXmlDStructureNode;
- const Pattern: String);
- destructor Destroy; override;
- function PatternMatchType(ELement: TXmlDElement):
- TElementPatternMatch;
- end;
-
- implementation
-
- {$R XMLTreeView.res}
-
- { Utility Functions }
-
- function CharEntitiesReplace(const S: String; CE: TCharEntities):
- String;
- begin
- Result := S;
- if ceAmp in CE then
- Result := StringReplace(Result, '&', '&', [rfReplaceAll]);
- if ceLt in CE then
- Result := StringReplace(Result, '<', '<', [rfReplaceAll]);
- if ceGt in CE then
- Result := StringReplace(Result, '>', '>', [rfReplaceAll]);
- if ceApos in CE then
- Result := StringReplace(Result, '''', ''', [rfReplaceAll]);
- if ceQuot in CE then
- Result := StringReplace(Result, '"', '"', [rfReplaceAll]);
- end;
-
- function ISOStrToDate(const Date: String): TDateTime;
- var
- WorkStr: String;
- Y: Word;
- M: Word;
- D: Word;
- begin
- WorkStr := StringReplace(Date, '-', '', [rfReplaceAll]);
- if Length(WorkStr) = 6 then
- WorkStr := Copy(FormatDateTime('yyyy', SysUtils.Date), 1, 2) +
- WorkStr;
- Y := StrToInt(Copy(WorkStr, 1, 4));
- M := StrToInt(Copy(WorkStr, 5, 2));
- D := StrToInt(Copy(WorkStr, 7, 2));
- Result := EncodeDate(Y, M, D);
- end;
-
- function ISOStrToTime(const Time: String): TDateTime;
- var
- H: Word;
- M: Word;
- S: Word;
- begin
- H := StrToInt(Copy(Time, 1, 2));
- M := StrToInt(Copy(Time, 4, 2));
- S := 0;
- if Length(Time) > 5 then
- S := StrToInt(Copy(Time, 7, 2));
- Result := EncodeTime(H, M, S, 0);
- end;
-
- function ISOStrToDateTime(const Value: String): TDateTime;
- var
- I: Integer;
- Date: String;
- Time: String;
- begin
- I := Pos('T', Value);
- if I > 0 then
- begin
- Date := Copy(Value, 1, (I - 1));
- Time := Copy(Value, (I + 1), $7FFF);
- end
- else
- Date := Value;
- try
- Result := ISOStrToDate(Date) + ISOStrToTime(Time);
- except
- raise EXmlDError.Create('Invalid ISO date/time string ' +
- 'encountered: ' + Value);
- end;
- end;
-
- function ISODateToStr(Value: TDateTime): String;
- begin
- Result := FormatDateTime('yyyy-mm-dd', Value);
- end;
-
- function ISODateTimeToStr(Value: TDateTime): String;
- begin
- Result := FormatDateTime('yyyy-mm-dd"T"hh:nn:ss', Value);
- end;
-
- function ISOTimeToStr(Value: TDateTime): String;
- begin
- Result := FormatDateTime('hh:nn:ss', Value);
- end;
-
- { EXmlDParseError }
-
- constructor EXmlDParseError.Create(ParseError: IXMLDOMParseError);
- begin
- inherited Create('XML Parse Error');
- FErrorCode := ParseError.errorCode;
- FReason := ParseError.reason;
- FSrcText := ParseError.srcText;
- FLine := ParseError.line;
- FLinePos := ParseError.linePos;
- end;
-
- procedure EXmlDParseError.ShowParseError;
- var
- S: String;
- begin
- S := 'XML Parse Error:' + FReason +
- 'Line=' + IntToStr(FLine) +
- ' LinePos=' + IntToStr(FLinePos);
- MessageDlg(S, mtError, [mbOK], 0);
- end;
-
- { TXmlDNode }
-
- procedure TXmlDNode.AppendChild(NewNode: TXmlDNode);
- begin
- raise EXmlDError.Create('AppendChild operation requested on ' +
- 'invalid node type');
- end;
-
- constructor TXmlDNode.Create;
- begin
- inherited Create;
- end;
-
- function TXmlDNode.GetFirstChild: TXmlDNode;
- begin
- Result := nil;
- end;
-
- function TXmlDNode.GetLastChild: TXmlDNode;
- begin
- Result := nil;
- end;
-
- function TXmlDNode.GetNodeName: TXmlName;
- begin
- Result := XmlNodeNames[FNodeType];
- end;
-
- function TXmlDNode.GetNodeValue: String;
- begin
- Result := '';
- end;
-
- function TXmlDNode.GetOwnerDocument: TXmlDDocument;
- var
- ANode: TXmlDStructureNode;
- begin
- ANode := TXmlDStructureNode(Self);
- while ANode.FParentNode <> nil do
- ANode := ANode.FParentNode;
- Result := ANode as TXmlDDocument;
- end;
-
- function TXmlDNode.HasChildNodes: Boolean;
- begin
- Result := False;
- end;
-
- procedure TXmlDNode.InsertBefore(NewNode, ThisNode: TXmlDNode);
- begin
- raise EXmlDError.Create('InsertBefore operation requested on ' +
- 'invalid node type');
- end;
-
- function TXmlDNode.RemoveChild(ThisNode: TXmlDNode): TXmlDNode;
- begin
- raise EXmlDError.Create('RemoveChild operation requested on ' +
- 'invalid node type');
- end;
-
- function TXmlDNode.ReplaceChild(NewNode, OldNode: TXmlDNode):
- TXmlDNode;
- begin
- raise EXmlDError.Create('ReplaceChild operation requested on ' +
- 'invalid node type');
- end;
-
- procedure TXmlDNode.SetLevel(Lvl: Integer);
- procedure SetLvl(Node: TXmlDNode; Lvl: Integer);
- var
- ChildNode: TXmlDNode;
- begin
- Node.FLevel := Lvl;
- ChildNode := Node.FirstChild;
- while ChildNode <> nil do
- begin
- SetLvl(ChildNode, (Lvl + 1));
- ChildNode := ChildNode.NextSibling;
- end;
- end;
- begin
- SetLvl(Self, Lvl);
- end;
-
- procedure TXmlDNode.SetNodeName(const Value: TXmlName);
- begin
- end;
-
- procedure TXmlDNode.SetNodeValue(const Value: String);
- begin
- end;
-
- procedure TXmlDNode.SetParent(ParentNode: TXmlDStructureNode);
- begin
- if (FParentNode <> nil) and (NodeType = xntElement) then
- Dec(FParentNode.FElementCount);
- FParentNode := ParentNode;
- if FParentNode <> nil then
- SetLevel(FParentNode.FLevel + 1)
- else
- SetLevel(0);
- if (FParentNode <> nil) and (NodeType = xntElement) then
- Inc(FParentNode.FElementCount);
- end;
-
- procedure TXmlDNode.WriteFormattedPrefix(Stream: TStream);
- var
- S: String;
- begin
- S := StringOfChar(' ', (Level - 1) * 2);
- Stream.WriteBuffer(Pointer(S)^, Length(S));
- end;
-
- procedure TXmlDNode.WriteFormattedSuffix(Stream: TStream);
- const
- CRLF: String[3] = #13#10;
- begin
- Stream.WriteBuffer(CRLF[1], 2);
- end;
-
- procedure TXmlDNode.ZeroAllTags;
- procedure ZeroTag(Node: TXmlDNode);
- var
- ChildNode: TXmlDNode;
- begin
- Node.Tag := 0;
- ChildNode := Node.FirstChild;
- while ChildNode <> nil do
- begin
- ZeroTag(ChildNode);
- ChildNode := ChildNode.NextSibling;
- end;
- end;
- begin
- ZeroTag(Self);
- end;
-
- { TXmlDStructureNode }
-
- procedure TXmlDStructureNode.AppendChild(NewNode: TXmlDNode);
- begin
- if NewNode.NodeType = xntDocumentFragment then
- AppendDocFragChild(TXmlDDocumentFragment(NewNode))
- else
- begin
- NewNode.SetParent(Self);
- if FFirstChild = nil then
- begin
- FFirstChild := NewNode;
- FLastChild := NewNode;
- end
- else
- begin
- FLastChild.FNextSibling := NewNode;
- NewNode.FPreviousSibling := FLastChild;
- FLastChild := NewNode;
- end;
- end;
- end;
-
- procedure TXmlDStructureNode.AppendDocFragChild(
- NewNode: TXmlDDocumentFragment);
- var
- CurrNode: TXmlDNode;
- NextNode: TXmlDNode;
- begin
- CurrNode := NewNode.FirstChild;
- while CurrNode <> nil do
- begin
- NextNode := CurrNode.NextSibling;
- AppendChild(NewNode.RemoveChild(CurrNode));
- CurrNode := NextNode;
- end;
- end;
-
- procedure TXmlDStructureNode.AssignAttrNodesToTreeNodes(
- ParXmlNode: TXmlDNode; ParTreeNode: TTreeNode);
- var
- I: Integer;
- S: String;
- TreeNode: TTreeNode;
- XSN: TXmlDStructureNode;
- begin
- XSN := ParXmlNode as TXmlDStructureNode;
- for I := 0 to (XSN.FAttrList.Count - 1) do
- begin
- S := StringReplace(XSN.FAttrList.List.Strings[I],
- '=', '="', []) + '"';
- TreeNode := ParTreeNode.Owner.AddChild(ParTreeNode, S);
- if ParXmlNode.NodeType = xntDocument then
- TreeNode.ImageIndex := 1
- else
- TreeNode.ImageIndex := 3;
- TreeNode.SelectedIndex := TreeNode.ImageIndex;
- TreeNode.Data := XSN.FAttrList;
- end;
- end;
-
- procedure TXmlDStructureNode.AssignNodeToTreeNode(XmlNode: TXmlDNode;
- TreeNode: TTreeNode);
- begin
- case XmlNode.NodeType of
- xntDocument:
- begin
- TreeNode.Text := 'XML Document';
- TreeNode.ImageIndex := 0;
- AssignAttrNodesToTreeNodes(XmlNode, TreeNode);
- end;
- xntElement:
- begin
- TreeNode.Text := XmlNode.NodeName;
- TreeNode.ImageIndex := 2;
- AssignAttrNodesToTreeNodes(XmlNode, TreeNode);
- end;
- xntText:
- begin
- TreeNode.Text := XmlNode.NodeValue;
- TreeNode.ImageIndex := 4;
- end;
- xntCDATASection:
- begin
- TreeNode.Text := XmlNode.NodeValue;
- TreeNode.ImageIndex := 5;
- end;
- xntComment:
- begin
- TreeNode.Text := XmlNode.NodeValue;
- TreeNode.ImageIndex := 6;
- end;
- xntDocumentFragment:
- begin
- TreeNode.Text := 'XML Document Fragment';
- TreeNode.ImageIndex := 0;
- end;
- end;
- TreeNode.SelectedIndex := TreeNode.ImageIndex;
- TreeNode.Data := XmlNode;
- end;
-
- procedure TXmlDStructureNode.AssignTo(Dest: TPersistent);
- var
- TV: TTreeView;
- TN: TTreeNodes;
- TreeNode: TTreeNode;
-
- procedure AddChildNodes(ParXmlNode: TXmlDNode;
- ParTreeNode: TTreeNode);
- var
- XmlNode: TXmlDNode;
- TreeNode: TTreeNode;
- begin
- XmlNode := ParXmlNode.FirstChild;
- while (XmlNode <> nil) do
- begin
- TreeNode := TN.AddChild(ParTreeNode, '');
- AssignNodeToTreeNode(XmlNode, TreeNode);
- AddChildNodes(XmlNode, TreeNode);
- XmlNode := XmlNode.NextSibling;
- end;
- end;
-
- begin
- if Dest is TTreeNodes then
- begin
- TN := TTreeNodes(Dest);
- TV := TTreeView(TN.Owner);
- TV.SortType := stNone;
- TV.ReadOnly := True;
- if TV.Images = nil then
- TV.Images := TCustomImageList.Create(TV);
- TV.Images.Clear;
- TV.Images.GetResource(rtBitmap,
- 'XMLTREEVIEWNODES', 0, [], 0);
- TV.Images.BkColor := clBlack;
- TN.BeginUpdate;
- TreeNode := TN.AddChild(nil, '');
- AssignNodeToTreeNode(Self, TreeNode);
- AddChildNodes(Self, TreeNode);
- TN.EndUpdate;
- end
- else
- inherited AssignTo(Dest);
- end;
-
- procedure TXmlDStructureNode.CloneChildren(FromNode: TXmlDStructureNode);
- var
- N: TXmlDNode;
- begin
- N := FromNode.FFirstChild;
- while N <> nil do
- begin
- AppendChild(N.CloneNode(True));
- N := N.NextSibling;
- end;
- end;
-
- constructor TXmlDStructureNode.Create;
- begin
- FAttrList := TXmlDAttrList.Create;
- FAttrList.FOwnerNode := Self;
- end;
-
- destructor TXmlDStructureNode.Destroy;
- var
- Node: TXmlDNode;
- NextNode: TXmlDNode;
- begin
- Node := FFirstChild;
- while (Node <> nil) do
- begin
- NextNode := Node.FNextSibling;
- Node.Free;
- Node := NextNode;
- end;
- FAttrList.Free;
- inherited Destroy;
- end;
-
- function TXmlDStructureNode.GetElementByName(
- const Name: String): TXmlDElement;
- var
- ChildNode: TXmlDElement;
- begin
- Result := nil;
- ChildNode := GetFirstChildElement;
- while ((ChildNode <> nil) and (Result = nil)) do
- begin
- if ChildNode.NodeName = Name then
- Result := ChildNode;
- ChildNode := ChildNode.GetNextSiblingElement;
- end;
- if Result = nil then
- raise EXmlDError.Create('Invalid GetElementByName call ' +
- 'for element named ' + Name);
- end;
-
- function TXmlDStructureNode.GetElements(Index: Integer): TXmlDElement;
- var
- I: Integer;
- ChildNode: TXmlDElement;
- begin
- if (Index < 0) or (Index >= ElementCount) then
- raise EXmlDError.Create('Invalid GetElements call ' +
- 'using index value of ' + IntToStr(Index));
- Result := nil;
- I := -1;
- ChildNode := GetFirstChildElement;
- while ((ChildNode <> nil) and (Result = nil)) do
- begin
- Inc(I);
- if I = Index then
- Result := ChildNode;
- ChildNode := ChildNode.GetNextSiblingElement;
- end;
- end;
-
- function TXmlDStructureNode.GetFirstChild: TXmlDNode;
- begin
- Result := FFirstChild;
- end;
-
- function TXmlDStructureNode.GetFirstChildElement: TXmlDElement;
- var
- ChildNode: TXmlDNode;
- begin
- Result := nil;
- ChildNode := FirstChild;
- while ((ChildNode <> nil) and (Result = nil)) do
- begin
- if ChildNode.NodeType = xntElement then
- Result := TXmlDELement(ChildNode);
- ChildNode := ChildNode.NextSibling;
- end;
- end;
-
- function TXmlDStructureNode.GetLastChild: TXmlDNode;
- begin
- Result := FLastChild;
- end;
-
- function TXmlDStructureNode.HasChildNodes: Boolean;
- begin
- Result := FFirstChild <> nil;
- end;
-
- procedure TXmlDStructureNode.InsertBefore(NewNode, ThisNode: TXmlDNode);
- var
- Node: TXmlDNode;
- begin
- if ThisNode = nil then
- AppendChild(NewNode)
- else
- begin
- Node := FFirstChild;
- while ((Node <> nil) and (Node <> ThisNode)) do
- Node := Node.FNextSibling;
- if Node = nil then
- AppendChild(NewNode)
- else
- begin
- if NewNode.NodeType = xntDocumentFragment then
- InsertDocFragBefore(TXmlDDocumentFragment(NewNode), ThisNode)
- else
- begin
- if ThisNode = FFirstChild then
- FFirstChild := NewNode;
- if ThisNode.FPreviousSibling <> nil then
- ThisNode.FPreviousSibling.FNextSibling := NewNode;
- NewNode.FPreviousSibling := ThisNode.FPreviousSibling;
- ThisNode.FPreviousSibling := NewNode;
- NewNode.FNextSibling := ThisNode;
- NewNode.SetParent(Self);
- end;
- end;
- end;
- end;
-
- procedure TXmlDStructureNode.InsertDocFragBefore(
- NewNode: TXmlDDocumentFragment; ThisNode: TXmlDNode);
- var
- CurrNode: TXmlDNode;
- begin
- CurrNode := NewNode.FirstChild;
- while CurrNode <> nil do
- begin
- InsertBefore(NewNode.RemoveChild(CurrNode), ThisNode);
- CurrNode := NewNode.FirstChild;
- end;
- end;
-
- function TXmlDStructureNode.RemoveChild(ThisNode: TXmlDNode): TXmlDNode;
- begin
- Result := FFirstChild;
- while ((Result <> nil) and (Result <> ThisNode)) do
- Result := Result.FNextSibling;
- if Result <> nil then
- begin
- if FFirstChild = FLastChild then
- begin
- FFirstChild := nil;
- FLastChild := nil;
- end
- else if Result = FFirstChild then
- begin
- FFirstChild := FFirstChild.FNextSibling;
- FFirstChild.FPreviousSibling := nil;
- end
- else if Result = FLastChild then
- begin
- FLastChild := FLastChild.FPreviousSibling;
- FLastChild.FNextSibling := nil;
- end
- else
- begin
- Result.FPreviousSibling.FNextSibling := Result.FNextSibling;
- Result.FNextSibling.FPreviousSibling := Result.FPreviousSibling;
- end;
- Result.FNextSibling := nil;
- Result.FPreviousSibling := nil;
- Result.SetParent(nil);
- end;
- end;
-
- function TXmlDStructureNode.ReplaceChild(NewNode,
- OldNode: TXmlDNode): TXmlDNode;
- var
- NextNode: TXmlDNode;
- begin
- if OldNode = FLastChild then
- begin
- Result := RemoveChild(OldNode);
- AppendChild(NewNode);
- end
- else
- begin
- NextNode := OldNode.FNextSibling;
- Result := RemoveChild(OldNode);
- InsertBefore(NewNode, NextNode);
- end;
- end;
-
- procedure TXmlDStructureNode.WriteChildrenToStream(Stream: TStream;
- FormattedForPrint: Boolean);
- var
- N: TXmlDNode;
- begin
- N := FFirstChild;
- while (N <> nil) do
- begin
- N.WriteToStream(Stream, FormattedForPrint);
- N := N.FNextSibling;
- end;
- end;
-
- { TXmlDContentNode }
-
- function TXmlDContentNode.GetNodeValue: String;
- begin
- Result := FValue;
- end;
-
- procedure TXmlDContentNode.SetNodeValue(const Value: String);
- begin
- FValue := Value;
- end;
-
- { TXmlDDocument }
-
- procedure TXmlDDocument.AppendChild(NewNode: TXmlDNode);
- begin
- if NewNode.NodeType = xntElement then
- begin
- if FDocumentElement <> nil then
- raise EXmlDError.Create('Second document element add attempted');
- FDocumentElement := TXmlDElement(NewNode);
- end;
- inherited AppendChild(NewNode);
- end;
-
- procedure TXmlDDocument.Clear;
- var
- Node: TXmlDNode;
- NextNode: TXmlDNode;
- begin
- Node := FFirstChild;
- while (Node <> nil) do
- begin
- NextNode := Node.FNextSibling;
- Node.Free;
- Node := NextNode;
- end;
- FFirstChild := nil;
- FLastChild := nil;
- FDocumentElement := nil;
- end;
-
- function TXmlDDocument.CloneNode(RecurseChildren: Boolean): TXmlDNode;
- var
- Clone: TXmlDDocument;
- begin
- Clone := TXmlDDocument.Create;
- if RecurseChildren then
- Clone.CloneChildren(Self);
- Result := Clone;
- end;
-
- constructor TXmlDDocument.Create;
- begin
- inherited Create;
- FNodeType := xntDocument;
- FAttrCharEntities := [ceQuot, ceAmp];
- FTextCharEntities := [ceLt, ceAmp];
- end;
-
- function TXmlDDocument.CreateCDATASection(
- const Text: String): TXmlDCDATASection;
- begin
- Result := TXmlDCDATASection.Create;
- Result.NodeValue := Text;
- end;
-
- function TXmlDDocument.CreateComment(const Text: String): TXmlDComment;
- begin
- Result := TXmlDComment.Create;
- Result.NodeValue := Text;
- end;
-
- function TXmlDDocument.CreateElement(
- const TagName: TXmlName): TXmlDElement;
- begin
- Result := TXmlDElement.Create;
- Result.NodeName := TagName;
- end;
-
- function TXmlDDocument.CreateElement(
- const TagName: TXmlName; const Data: String): TXmlDElement;
- begin
- Result := TXmlDElement.Create;
- Result.NodeName := TagName;
- if Data <> '' then
- Result.AppendChild(OwnerDocument.CreateTextNode(Data));
- end;
-
- function TXmlDDocument.CreateElement(const TagName: TXmlName;
- const Data: String; const AttrName: TXmlName;
- const AttrValue: String): TXmlDElement;
- begin
- Result := TXmlDElement.Create;
- Result.NodeName := TagName;
- if AttrName <> '' then
- Result.FAttrList.Values[AttrName] := AttrValue;
- if Data <> '' then
- Result.AppendChild(OwnerDocument.CreateTextNode(Data));
- end;
-
- function TXmlDDocument.CreateDocumentFragment: TXmlDDocumentFragment;
- begin
- Result := TXmlDDocumentFragment.Create;
- end;
-
- function TXmlDDocument.CreateElement(const TagName: TXmlName;
- const Data: String; const AttrNames: array of TXmlName;
- const AttrValues: array of String): TXmlDElement;
- var
- I: Integer;
- begin
- if (Low(AttrNames) <> Low(AttrValues)) or
- (High(AttrNames) <> High(AttrValues)) then
- raise EXmlDError.Create('Invalid CreateElement call');
- Result := TXmlDElement.Create;
- Result.NodeName := TagName;
- for I := Low(AttrNames) to High(AttrNames) do
- if AttrNames[I] <> '' then
- Result.FAttrList.Values[AttrNames[I]] := AttrValues[I];
- if Data <> '' then
- Result.AppendChild(OwnerDocument.CreateTextNode(Data));
- end;
-
- function TXmlDDocument.CreateTextNode(const Text: String): TXmlDText;
- begin
- Result := TXmlDText.Create;
- Result.NodeValue := Text;
- end;
-
- procedure TXmlDDocument.DecodePrologAttrs(S: String);
- var
- I: Integer;
- begin
- I := Pos(' ', S);
- while I > 0 do
- begin
- FAttrList.Add(StringReplace(
- Copy(S, 1, I - 1), '"', '', [rfReplaceAll]));
- S := TrimLeft(Copy(S, I + 1, $7FFF));
- I := Pos(' ', S);
- end;
- FAttrList.Add(StringReplace(S, '"', '', [rfReplaceAll]));
- end;
-
- procedure TXmlDDocument.InsertBefore(NewNode, ThisNode: TXmlDNode);
- begin
- if NewNode.NodeType = xntElement then
- begin
- if FDocumentElement <> nil then
- raise EXmlDError.Create('Second document element add attempted');
- FDocumentElement := TXmlDElement(NewNode);
- end;
- inherited InsertBefore(NewNode, ThisNode);
- end;
-
- procedure TXmlDDocument.LoadAttributes(Node: TXmlDElement;
- DOMNode: IXMLDOMNode);
- var
- I: Integer;
- Attributes: IXMLDOMNamedNodeMap;
- Item: IXMLDOMNode;
- begin
- Attributes := DOMNode.attributes;
- for I := 0 to (Attributes.length - 1) do
- begin
- Item := Attributes[I];
- Node.FAttrList[Item.nodeName] := Item.nodeValue;
- end;
- end;
-
- procedure TXmlDDocument.LoadChildNodes(ParNode: TXmlDNode;
- ParDOMNode: IXMLDOMNode);
- var
- ChildDOMNode: IXMLDOMNode;
- NewNode: TXmlDNode;
- begin
- ChildDOMNode := ParDOMNode.firstChild;
- while ChildDOMNode <> nil do
- begin
- NewNode := nil;
- case ChildDOMNode.nodeType of
- NODE_ELEMENT:
- begin
- NewNode := CreateElement(ChildDOMNode.nodeName);
- LoadAttributes(TXmlDElement(NewNode), ChildDOMNode);
- end;
- NODE_TEXT:
- NewNode := CreateTextNode(ChildDOMNode.nodeValue);
- NODE_CDATA_SECTION:
- NewNode := CreateCDataSection(ChildDOMNode.nodeValue);
- NODE_PROCESSING_INSTRUCTION:
- DecodePrologAttrs(ChildDOMNode.nodeValue);
- NODE_COMMENT:
- NewNode := CreateComment(ChildDOMNode.nodeValue);
- NODE_DOCUMENT_TYPE:
- TXmlDDocument(ParNode).DocumentTypeDefinition :=
- ChildDOMNode.xml;
- else
- if not DiscardUnsupportedItems then
- raise EXmlDError.Create('XML document contains unsupported ' +
- 'node type of ' + ChildDOMNode.nodeTypeString);
- end;
- if (NewNode <> nil) and (ParNode <> nil) then
- ParNode.AppendChild(NewNode);
- LoadChildNodes(NewNode, ChildDOMNode);
- ChildDOMNode := ChildDOMNode.NextSibling;
- end;
- end;
-
- procedure TXmlDDocument.LoadFromDOMDocument(Doc: IXMLDOMDocument);
- var
- Err: IXMLDOMParseError;
- begin
- Clear;
- Err := Doc.parseError;
- if Err.errorCode <> 0 then
- raise EXmlDParseError.Create(Err);
- NodeName := Doc.nodeName;
- LoadChildNodes(Self, Doc);
- end;
-
- procedure TXmlDDocument.LoadFromFile(const FileName: String;
- ValidateOnParse, DiscardUnsupportedItems: Boolean);
- var
- Doc: IXMLDOMDocument;
- begin
- Doc := CoDOMDocument.Create;
- Doc.validateOnParse := ValidateOnParse;
- Self.DiscardUnsupportedItems := DiscardUnsupportedItems;
- Doc.async := False;
- Doc.load(FileName);
- LoadFromDOMDocument(Doc);
- end;
-
- procedure TXmlDDocument.LoadFromStream(Stream: TStream; ValidateOnParse,
- DiscardUnsupportedItems: Boolean);
- var
- Doc: IXMLDOMDocument;
- SS: TStringStream;
- begin
- Doc := CoDOMDocument.Create;
- Doc.validateOnParse := ValidateOnParse;
- Self.DiscardUnsupportedItems := DiscardUnsupportedItems;
- if Stream is TStringStream then
- SS := TStringStream(Stream)
- else
- begin
- SS := TStringStream.Create('');
- SS.CopyFrom(Stream, Stream.Size);
- end;
- SS.Position := 0;
- Doc.loadXML(PChar(SS.DataString));
- LoadFromDOMDocument(Doc);
- if SS <> Stream then
- SS.Free
- else
- SS.Position := 0;
- end;
-
- function TXmlDDocument.RemoveChild(ThisNode: TXmlDNode): TXmlDNode;
- begin
- if ThisNode = FDocumentElement then
- FDocumentElement := nil;
- Result := inherited RemoveChild(ThisNode);
- end;
-
- function TXmlDDocument.ReplaceChild(NewNode,
- OldNode: TXmlDNode): TXmlDNode;
- begin
- if OldNode = FDocumentElement then
- FDocumentElement := nil;
- if NewNode.NodeType = xntElement then
- FDocumentElement := TXmlDElement(NewNode);
- Result := inherited ReplaceChild(NewNode, OldNode);
- end;
-
- procedure TXmlDDocument.SaveToFile(const FileName: String;
- FormattedForPrint: Boolean);
- var
- Stream: TStream;
- begin
- Stream := TFileStream.Create(FileName, fmCreate);
- try
- SaveToStream(Stream);
- finally
- Stream.Free;
- end;
- end;
-
- procedure TXmlDDocument.SaveToStream(Stream: TStream;
- FormattedForPrint: Boolean = False);
- begin
- WriteToStream(Stream, FormattedForPrint);
- end;
-
- procedure TXmlDDocument.WritePrologToStream(Stream: TStream);
- var
- S: String;
- AttrVal: String;
- begin
- S := '<?xml version=';
- AttrVal := FAttrList['version'];
- if AttrVal <> '' then
- AppendStr(S, '"' + AttrVal + '"')
- else
- AppendStr(S, '"1.0"');
- AttrVal := FAttrList['encoding'];
- if AttrVal <> '' then
- AppendStr(S, ' encoding=' + '"' + AttrVal + '"');
- AttrVal := FAttrList['standalone'];
- if AttrVal <> '' then
- AppendStr(S, ' standalone=' + '"' + AttrVal + '"');
- AppendStr(S, '?>');
- Stream.WriteBuffer(Pointer(S)^, Length(S));
- end;
-
- procedure TXmlDDocument.WriteToStream(Stream: TStream;
- FormattedForPrint: Boolean);
- begin
- WritePrologToStream(Stream);
- if FormattedForPrint then
- WriteFormattedSuffix(Stream);
- if FDocumentTypeDefinition <> '' then
- begin
- Stream.WriteBuffer(Pointer(FDocumentTypeDefinition)^,
- Length(FDocumentTypeDefinition));
- if FormattedForPrint then
- WriteFormattedSuffix(Stream);
- end;
- WriteChildrenToStream(Stream, FormattedForPrint);
- end;
-
- { TXmlDElement }
-
- function TXmlDElement.CloneNode(RecurseChildren: Boolean): TXmlDNode;
- var
- Clone: TXmlDElement;
- begin
- Clone := TXmlDElement.Create;
- Clone.FNodeName := FNodeName;
- Clone.FAttrList.Assign(FAttrList);
- if RecurseChildren then
- Clone.CloneChildren(Self);
- Result := Clone;
- end;
-
- constructor TXmlDElement.Create;
- begin
- inherited Create;
- FNodeType := xntElement;
- end;
-
- function TXmlDElement.GetAsBoolean: Boolean;
- begin
- Result := GetFirstTextNodeValue = '1';
- end;
-
- function TXmlDElement.GetAsCurrency: Currency;
- begin
- Result := StrToCurr(GetFirstTextNodeValue);
- end;
-
- function TXmlDElement.GetAsDate: TDateTime;
- begin
- Result := ISOStrToDate(GetFirstTextNodeValue);
- end;
-
- function TXmlDElement.GetAsDateTime: TDateTime;
- begin
- Result := ISOStrToDateTime(GetFirstTextNodeValue);
- end;
-
- function TXmlDElement.GetAsInteger: Integer;
- begin
- Result := StrToInt(GetFirstTextNodeValue);
- end;
-
- function TXmlDElement.GetAsString: String;
- begin
- Result := GetFirstTextNodeValue;
- end;
-
- function TXmlDElement.GetAsTime: TDateTime;
- begin
- Result := ISOStrToTime(GetFirstTextNodeValue);
- end;
-
- function TXmlDElement.GetFirstTextNodeValue: String;
- var
- TextNode: TXmlDNode;
- begin
- TextNode := FirstChild;
- if (TextNode = nil) or (TextNode.NodeType <> xntText) then
- raise EXmlDError.Create('Invalid GetAsXxx call');
- Result := TextNode.NodeValue;
- end;
-
- function TXmlDElement.GetNextSiblingElement: TXmlDElement;
- var
- NextNode: TXmlDNode;
- begin
- Result := nil;
- NextNode := NextSibling;
- while ((NextNode <> nil) and (Result = nil)) do
- begin
- if NextNode.NodeType = xntElement then
- Result := TXmlDELement(NextNode);
- NextNode := NextNode.NextSibling;
- end;
- end;
-
- function TXmlDElement.GetNodeName: TXmlName;
- begin
- Result := FNodeName;
- end;
-
- procedure TXmlDElement.SetAsBoolean(const Value: Boolean);
- const
- BoolStrVal: array[False..True] of String = ('0', '1');
- begin
- SetFirstTextNodeValue(BoolStrVal[Value]);
- end;
-
- procedure TXmlDElement.SetAsCurrency(const Value: Currency);
- begin
- SetFirstTextNodeValue(CurrToStr(Value));
- end;
-
- procedure TXmlDElement.SetAsDate(const Value: TDateTime);
- begin
- SetFirstTextNodeValue(ISODateToStr(Value));
- end;
-
- procedure TXmlDElement.SetAsDateTime(const Value: TDateTime);
- begin
- SetFirstTextNodeValue(ISODateTimeToStr(Value));
- end;
-
- procedure TXmlDElement.SetAsInteger(const Value: Integer);
- begin
- SetFirstTextNodeValue(IntToStr(Value));
- end;
-
- procedure TXmlDElement.SetAsString(const Value: String);
- begin
- SetFirstTextNodeValue(Value);
- end;
-
- procedure TXmlDElement.SetAsTime(const Value: TDateTime);
- begin
- SetFirstTextNodeValue(ISOTimeToStr(Value));
- end;
-
- procedure TXmlDElement.SetFirstTextNodeValue(const Value: String);
- var
- TextNode: TXmlDNode;
- begin
- TextNode := FirstChild;
- if TextNode = nil then
- begin
- TextNode := TXmlDText.Create;
- TextNode.NodeValue := Value;
- AppendChild(TextNode);
- end
- else
- begin
- if TextNode.NodeType <> xntText then
- raise EXmlDError.Create('Invalid SetAsXxx call');
- TextNode.NodeValue := Value;
- end;
- end;
-
- procedure TXmlDElement.SetNodeName(const Value: TXmlName);
- begin
- FNodeName := Value;
- end;
-
- procedure TXmlDElement.WriteToStream(Stream: TStream;
- FormattedForPrint: Boolean);
- var
- S: String;
- Formatted: Boolean;
- begin
- Formatted := FormattedForPrint;
- if Formatted then
- begin
- if (FFirstChild <> nil) and (FFirstChild = FLastChild) and
- (FFirstChild.NodeType = xntText) and
- (Length(FFirstChild.NodeValue) < 48) then
- Formatted := False;
- WriteFormattedPrefix(Stream);
- end;
- S := '<' + FNodeName;
- Stream.WriteBuffer(Pointer(S)^, Length(S));
- if FAttrList.Count > 0 then
- FAttrList.WriteToStream(Stream);
- if FFirstChild <> nil then
- begin
- S := '>';
- Stream.WriteBuffer(Pointer(S)^, 1);
- if Formatted then
- WriteFormattedSuffix(Stream);
- end;
- if FFirstChild = nil then
- S := '/>'
- else
- begin
- WriteChildrenToStream(Stream, Formatted);
- if Formatted then
- WriteFormattedPrefix(Stream);
- S := '</' + FNodeName + '>';
- end;
- Stream.WriteBuffer(Pointer(S)^, Length(S));
- if FormattedForPrint then
- WriteFormattedSuffix(Stream);
- end;
-
- { TXmlDDocumentFragment }
-
- function TXmlDDocumentFragment.CloneNode(
- RecurseChildren: Boolean): TXmlDNode;
- var
- Clone: TXmlDDocumentFragment;
- begin
- Clone := TXmlDDocumentFragment.Create;
- if RecurseChildren then
- Clone.CloneChildren(Self);
- Result := Clone;
- end;
-
- constructor TXmlDDocumentFragment.Create;
- begin
- inherited Create;
- FNodeType := xntDocumentFragment;
- end;
-
- procedure TXmlDDocumentFragment.WriteToStream(Stream: TStream;
- FormattedForPrint: Boolean);
- begin
- end;
-
- { TXmlDText }
-
- function TXmlDText.CloneNode(RecurseChildren: Boolean): TXmlDNode;
- begin
- Result := TXmlDText.Create;
- Result.NodeValue := NodeValue;
- end;
-
- constructor TXmlDText.Create;
- begin
- inherited Create;
- FNodeType := xntText;
- end;
-
- procedure TXmlDText.WriteToStream(Stream: TStream;
- FormattedForPrint: Boolean);
- var
- S: String;
- Skip: Boolean;
- D: TXmlDDocument;
- begin
- if FormattedForPrint then
- WriteFormattedPrefix(Stream);
- S := FValue;
- Skip := False;
- D := OwnerDocument;
- if Assigned(D.FOnOutputTextValue) then
- D.FOnOutputTextValue(Self, S, Skip);
- if (not Skip) and (D.FTextCharEntities <> []) then
- S := CharEntitiesReplace(S, D.FTextCharEntities);
- Stream.WriteBuffer(Pointer(S)^, Length(S));
- if FormattedForPrint then
- WriteFormattedSuffix(Stream);
- end;
-
- { TXmlDComment }
-
- function TXmlDComment.CloneNode(RecurseChildren: Boolean): TXmlDNode;
- begin
- Result := TXmlDComment.Create;
- Result.NodeValue := NodeValue;
- end;
-
- constructor TXmlDComment.Create;
- begin
- inherited Create;
- FNodeType := xntComment;
- end;
-
- procedure TXmlDComment.WriteToStream(Stream: TStream;
- FormattedForPrint: Boolean);
- var
- S: String;
- begin
- if FormattedForPrint then
- WriteFormattedPrefix(Stream);
- S := '<!--' + FValue + '-->';
- Stream.WriteBuffer(Pointer(S)^, Length(S));
- if FormattedForPrint then
- WriteFormattedSuffix(Stream);
- end;
-
- { TXmlCDATASection }
-
- function TXmlDCDATASection.CloneNode(RecurseChildren: Boolean): TXmlDNode;
- begin
- Result := TXmlDCDATASection.Create;
- Result.NodeValue := NodeValue;
- end;
-
- constructor TXmlDCDATASection.Create;
- begin
- inherited Create;
- FNodeType := xntCDATASection;
- end;
-
- procedure TXmlDCDATASection.WriteToStream(Stream: TStream;
- FormattedForPrint: Boolean);
- var
- S: String;
- begin
- if FormattedForPrint then
- WriteFormattedPrefix(Stream);
- S := '<![CDATA[' + FValue + ']]>';
- Stream.WriteBuffer(Pointer(S)^, Length(S));
- if FormattedForPrint then
- WriteFormattedSuffix(Stream);
- end;
-
- { TXmlDAttrList }
-
- function TXmlDAttrList.Add(const S: String): Integer;
- begin
- Result := List.Add(S);
- end;
-
- procedure TXmlDAttrList.Assign(Source: TPersistent);
- begin
- if Source is TXmlDAttrList then
- List.Assign(TXmlDAttrList(Source).List);
- end;
-
- procedure TXmlDAttrList.Clear;
- begin
- List.Clear;
- end;
-
- constructor TXmlDAttrList.Create;
- begin
- inherited Create;
- List := TStringList.Create;
- end;
-
- destructor TXmlDAttrList.Destroy;
- begin
- List.Free;
- inherited Destroy;
- end;
-
- function TXmlDAttrList.GetCount: Integer;
- begin
- Result := List.Count;
- end;
-
- function TXmlDAttrList.GetNames(Index: Integer): TXmlName;
- begin
- Result := List.Names[Index];
- end;
-
- function TXmlDAttrList.GetValues(const Name: TXmlName): String;
- begin
- Result := List.Values[Name];
- end;
-
- procedure TXmlDAttrList.SetValues(const Name: TXmlName;
- const Value: String);
- begin
- List.Values[Name] := Value;
- end;
-
- procedure TXmlDAttrList.WriteToStream(Stream: TStream);
- var
- I: Integer;
- J: Integer;
- S: String;
- Val: String;
- Skip: Boolean;
- D: TXmlDDocument;
- begin
- D := FOwnerNode.OwnerDocument;
- for I := 0 to (List.Count - 1) do
- begin
- S := List[I];
- J := Pos('=', S);
- Val := Copy(S, J + 1, $7FFF);
- Skip := False;
- if Assigned(D.FOnOutputAttrValue) then
- D.FOnOutputAttrValue(Self, Val, Skip);
- if (not Skip) and (D.FAttrCharEntities <> []) then
- Val := CharEntitiesReplace(Val, D.FAttrCharEntities);
- S := ' ' + Copy(S, 1, J) + '"' + Val + '"';
- Stream.WriteBuffer(Pointer(S)^, Length(S));
- end;
- end;
-
- { TXmlElementIterator }
-
- constructor TXmlDElementIterator.Create(ContextNode: TXmlDStructureNode;
- const Pattern: String);
- begin
- inherited Create;
- Position := TList.Create;
- RootNode := ContextNode;
- CurrNode := ContextNode;
- if Pattern <> '' then
- ElementPattern := TXmlDElementPattern.Create(RootNode, Pattern);
- end;
-
- destructor TXmlDElementIterator.Destroy;
- begin
- ElementPattern.Free;
- Position.Free;
- inherited Destroy;
- end;
-
- function TXmlDElementIterator.Next: TXmlDElement;
- begin
- Result := nil;
- if CurrNode = nil then
- Exit;
- if ElementPattern = nil then
- Result := NextElementInStructure
- else
- Result := NextElementInPattern;
- end;
-
- function TXmlDElementIterator.NextElementInPattern: TXmlDElement;
-
- function GetFirstElementInPattern(StartNode: TXmlDStructureNode):
- TXmlDElement;
- var
- CandidateElement: TXmlDElement;
- begin
- Result := nil;
- if StartNode.ElementCount > 0 then
- begin
- CandidateElement := StartNode.GetFirstChildElement;
- while ((CandidateElement <> nil) and (Result = nil)) do
- begin
- case ElementPattern.PatternMatchType(CandidateElement) of
- epmEndMatch:
- Result := CandidateElement;
- epmPathMatch:
- Result := GetFirstElementInPattern(CandidateElement);
- end;
- if Result = nil then
- CandidateElement := CandidateElement.GetNextSiblingElement;
- end;
- end;
- end;
-
- function GetNextElementInPattern:TXmlDElement;
- var
- CandidateElement: TXmlDElement;
-
- function GetNextCandidate(StartNode: TXmlDStructureNode): TXmlDElement;
- begin
- Result := TXmlDElement(StartNode).GetNextSiblingElement;
- if Result = nil then
- begin
- if StartNode.ParentNode <> RootNode then
- begin
- Result := TXmlDElement(StartNode.ParentNode).
- GetNextSiblingElement;
- if Result = nil then
- Result := GetNextCandidate(StartNode.ParentNode);
- end;
- end;
- end;
-
- begin
- Result := GetFirstElementInPattern(CurrNode);
- if Result <> nil then
- Exit;
- CandidateElement := GetNextCandidate(CurrNode);
- while ((CandidateElement <> nil) and (Result = nil)) do
- begin
- if CandidateElement <> nil then
- begin
- case ElementPattern.PatternMatchType(CandidateElement) of
- epmEndMatch:
- Result := CandidateElement;
- epmPathMatch:
- Result := GetFirstElementInPattern(CandidateElement);
- end;
- if Result = nil then
- CandidateElement := GetNextCandidate(CandidateElement);
- end;
- end;
- end;
-
- begin
- if CurrNode = RootNode then
- Result := GetFirstElementInPattern(RootNode)
- else
- Result := GetNextElementInPattern;
- CurrNode := Result;
- end;
-
- function TXmlDElementIterator.NextElementInStructure: TXmlDElement;
- begin
- if CurrNode = RootNode then
- Result := RootNode.GetFirstChildElement
- else
- begin
- if CurrNode.ElementCount > 0 then
- begin
- Result := CurrNode.GetFirstChildElement;
- end
- else
- begin
- Result := TXmlDElement(CurrNode).GetNextSiblingElement;
- if Result = nil then
- begin
- while (Result = nil) do
- begin
- CurrNode := CurrNode.ParentNode;
- if CurrNode = RootNode then
- Break;
- Result := TXmlDElement(CurrNode).GetNextSiblingElement;
- end;
- end;
- end;
- end;
- CurrNode := Result;
- end;
-
- procedure TXmlDElementIterator.Reset(ContextNode: TXmlDStructureNode;
- const Pattern: String);
- begin
- RootNode := ContextNode;
- CurrNode := ContextNode;
- ElementPattern.Free;
- ElementPattern := nil;
- if Pattern <> '' then
- ElementPattern := TXmlDElementPattern.Create(RootNode, Pattern);
- end;
-
- { TXmlDElementPattern }
-
- constructor TXmlDElementPattern.Create(Contextnode: TXmlDStructureNode;
- const Pattern: String);
- begin
- inherited Create;
- RootNode := ContextNode;
- PatternPieces := TStringList.Create;
- ParsePattern(Pattern);
- end;
-
- destructor TXmlDElementPattern.Destroy;
- begin
- PatternPieces.Free;
- inherited Destroy;
- end;
-
- procedure TXmlDElementPattern.ParsePattern(const Pattern: String);
- var
- I: Integer;
- Lvl: Integer;
- S: String;
-
- procedure ParsePatternLevel(const Pattern: String);
- var
- I: Integer;
- S: String;
- begin
- S := Pattern;
- while (S <> '') do
- begin
- I := Pos('|', S);
- if I > 0 then
- begin
- PatternPieces.AddObject(Trim(Copy(S, 1, (I - 1))),
- Pointer(Lvl));
- S := Copy(S, (I + 1), $7FFF);
- end
- else
- begin
- PatternPieces.AddObject(Trim(S), Pointer(Lvl));
- S := '';
- end;
- end;
- end;
-
- begin
- PatternPieces.Clear;
- S := Pattern;
- Lvl := 0;
- while (S <> '') do
- begin
- Inc(Lvl);
- PatternLevels := Lvl;
- I := Pos('/', S);
- if I = 0 then
- begin
- ParsePatternLevel(S);
- S := '';
- end
- else
- begin
- ParsePatternLevel(Copy(S, 1, (I - 1)));
- S := Copy(S, (I + 1), $7FFF);
- end;
- end;
- end;
-
- function TXmlDElementPattern.PatternMatchType(Element: TXmlDElement):
- TElementPatternMatch;
- var
- I: Integer;
- Lvl: Integer;
- begin
- Result := epmNoMatch;
- Lvl := Element.Level - RootNode.Level;
- if Lvl > PatternLevels then
- Exit;
- for I := 0 to (PatternPieces.Count - 1) do
- begin
- if (Integer(PatternPieces.Objects[I]) = Lvl) and
- ((PatternPieces[I] = '*') or
- (PatternPieces[I] = Element.NodeName)) then
- begin
- Result := epmPathMatch;
- Break;
- end;
- end;
- if (Result = epmPathMatch) and (Lvl = PatternLevels) then
- Result := epmEndMatch;
- end;
-
- end.
-