XMLParse.pas 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. unit XMLParse;
  2. { XML parser. Currently just calls MSXML 6.0 to do the real work. }
  3. interface
  4. uses
  5. Windows, SysUtils, Variants;
  6. type
  7. IXMLNode = interface
  8. function GetAttribute(const AName: String): String;
  9. function GetOptionalAttribute(const AName: String): String;
  10. function GetFirstChild: IXMLNode;
  11. function GetNodeName: String;
  12. function GetNextSibling: IXMLNode;
  13. function GetNodeType: Integer;
  14. function GetParentNode: IXMLNode;
  15. function GetPreviousSibling: IXMLNode;
  16. function GetRealMSXMLNode: OleVariant;
  17. function GetText: String;
  18. function HasAttribute(const AName: String): Boolean;
  19. function TransformNode(const Stylesheet: IXMLNode): String;
  20. property Attributes[const AName: String]: String read GetAttribute;
  21. property OptionalAttributes[const AName: String]: String read GetOptionalAttribute;
  22. property FirstChild: IXMLNode read GetFirstChild;
  23. property NextSibling: IXMLNode read GetNextSibling;
  24. property NodeName: String read GetNodeName;
  25. property NodeType: Integer read GetNodeType;
  26. property ParentNode: IXMLNode read GetParentNode;
  27. property PreviousSibling: IXMLNode read GetPreviousSibling;
  28. property Text: String read GetText;
  29. end;
  30. TXMLDocument = class
  31. private
  32. FDoc: OleVariant;
  33. function GetRoot: IXMLNode;
  34. public
  35. constructor Create;
  36. procedure LoadFromFile(const AFilename: String);
  37. procedure StripComments;
  38. property Root: IXMLNode read GetRoot;
  39. end;
  40. const
  41. { Values for the NodeType property }
  42. NODE_INVALID = 0;
  43. NODE_ELEMENT = 1;
  44. NODE_ATTRIBUTE = 2;
  45. NODE_TEXT = 3;
  46. NODE_CDATA_SECTION = 4;
  47. NODE_ENTITY_REFERENCE = 5;
  48. NODE_ENTITY = 6;
  49. NODE_PROCESSING_INSTRUCTION = 7;
  50. NODE_COMMENT = 8;
  51. NODE_DOCUMENT = 9;
  52. NODE_DOCUMENT_TYPE = 10;
  53. NODE_DOCUMENT_FRAGMENT = 11;
  54. NODE_NOTATION = 12;
  55. implementation
  56. uses
  57. ActiveX, ComObj;
  58. type
  59. TXMLNode = class(TInterfacedObject, IXMLNode)
  60. private
  61. FRealNode: OleVariant;
  62. function GetFirstChild: IXMLNode;
  63. function GetAttribute(const AName: String): String;
  64. function GetOptionalAttribute(const AName: String): String;
  65. function GetNextSibling: IXMLNode;
  66. function GetNodeName: String;
  67. function GetNodeType: Integer;
  68. function GetParentNode: IXMLNode;
  69. function GetPreviousSibling: IXMLNode;
  70. function GetRealMSXMLNode: OleVariant;
  71. function GetText: String;
  72. function HasAttribute(const AName: String): Boolean;
  73. function TransformNode(const Stylesheet: IXMLNode): String;
  74. public
  75. constructor Create(const ARealNode: OleVariant);
  76. end;
  77. function IsVarAssigned(const AVariant: OleVariant): Boolean;
  78. begin
  79. case VarType(AVariant) of
  80. varEmpty: Result := False;
  81. varDispatch: Result := Assigned(TVarData(AVariant).VDispatch);
  82. else
  83. raise Exception.Create('IsVarAssigned: Unexpected variant type');
  84. end;
  85. end;
  86. function MakeNode(const ARealNode: OleVariant): IXMLNode;
  87. begin
  88. if IsVarAssigned(ARealNode) then
  89. Result := TXMLNode.Create(ARealNode)
  90. else
  91. Result := nil;
  92. end;
  93. function VariantToString(const V: OleVariant): String;
  94. begin
  95. if VarType(V) <> varOleStr then
  96. raise Exception.Create('VariantToUTF8String: Expected varOleStr');
  97. Result := TVarData(V).VOleStr;
  98. end;
  99. { TXMLDocument }
  100. constructor TXMLDocument.Create;
  101. begin
  102. inherited Create;
  103. FDoc := CreateOleObject('MSXML2.DOMDocument.6.0');
  104. FDoc.setProperty('ProhibitDTD', False);
  105. FDoc.resolveExternals := True;
  106. FDoc.async := False;
  107. FDoc.preserveWhitespace := True;
  108. end;
  109. function TXMLDocument.GetRoot: IXMLNode;
  110. begin
  111. Result := MakeNode(FDoc.documentElement);
  112. end;
  113. procedure TXMLDocument.LoadFromFile(const AFilename: String);
  114. begin
  115. if not FDoc.load(AFilename) then begin
  116. if Integer(FDoc.parseError.line) <> 0 then
  117. raise Exception.CreateFmt('XML parse error (line %d, column %d): %s',
  118. [Integer(FDoc.parseError.line), Integer(FDoc.parseError.linepos),
  119. FDoc.parseError.reason])
  120. else
  121. raise Exception.CreateFmt('XML parse error: %s', [FDoc.parseError.reason]);
  122. end;
  123. end;
  124. procedure TXMLDocument.StripComments;
  125. begin
  126. FDoc.selectNodes('//comment()').removeAll;
  127. end;
  128. { TXMLNode }
  129. constructor TXMLNode.Create(const ARealNode: OleVariant);
  130. begin
  131. inherited Create;
  132. FRealNode := ARealNode;
  133. end;
  134. function TXMLNode.GetAttribute(const AName: String): String;
  135. var
  136. N: OleVariant;
  137. begin
  138. N := FRealNode.attributes.getNamedItem(AName);
  139. if not IsVarAssigned(N) then
  140. raise Exception.CreateFmt('Attribute "%s" does not exist', [AName]);
  141. Result := VariantToString(N.value);
  142. end;
  143. function TXMLNode.GetOptionalAttribute(const AName: String): String;
  144. var
  145. N: OleVariant;
  146. begin
  147. N := FRealNode.attributes.getNamedItem(AName);
  148. if not IsVarAssigned(N) then
  149. Result := ''
  150. else
  151. Result := VariantToString(N.value);
  152. end;
  153. function TXMLNode.GetFirstChild: IXMLNode;
  154. begin
  155. Result := MakeNode(FRealNode.firstChild);
  156. end;
  157. function TXMLNode.GetNodeName: String;
  158. begin
  159. Result := VariantToString(FRealNode.nodeName);
  160. end;
  161. function TXMLNode.GetNextSibling: IXMLNode;
  162. begin
  163. Result := MakeNode(FRealNode.nextSibling);
  164. end;
  165. function TXMLNode.GetNodeType: Integer;
  166. begin
  167. Result := FRealNode.nodeType;
  168. end;
  169. function TXMLNode.GetParentNode: IXMLNode;
  170. begin
  171. Result := MakeNode(FRealNode.parentNode);
  172. end;
  173. function TXMLNode.GetPreviousSibling: IXMLNode;
  174. begin
  175. Result := MakeNode(FRealNode.previousSibling);
  176. end;
  177. function TXMLNode.GetRealMSXMLNode: OleVariant;
  178. begin
  179. Result := FRealNode;
  180. end;
  181. function TXMLNode.GetText: String;
  182. begin
  183. Result := VariantToString(FRealNode.text);
  184. end;
  185. function TXMLNode.HasAttribute(const AName: String): Boolean;
  186. begin
  187. Result := IsVarAssigned(FRealNode.attributes.getNamedItem(AName));
  188. end;
  189. function TXMLNode.TransformNode(const Stylesheet: IXMLNode): String;
  190. begin
  191. Result := VariantToString(FRealNode.transformNode(Stylesheet.GetRealMSXMLNode));
  192. end;
  193. end.