dom.pp 63 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250
  1. {
  2. This file is part of the Free Component Library
  3. Implementation of DOM interfaces
  4. Copyright (c) 1999-2000 by Sebastian Guenther, [email protected]
  5. Modified in 2006 by Sergei Gorelkin, [email protected]
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {
  13. This unit provides classes which implement the interfaces defined in the
  14. DOM (Document Object Model) specification.
  15. The current state is:
  16. DOM Level 1 - Almost completely implemented
  17. DOM Level 2 - Partially implemented
  18. Specification used for this implementation:
  19. "Document Object Model (DOM) Level 2 Specification Version 1.0
  20. W3C Recommendation 11 November, 2000"
  21. http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113
  22. }
  23. unit DOM;
  24. {$ifdef fpc}
  25. {$MODE objfpc}{$H+}
  26. {$endif}
  27. interface
  28. uses
  29. SysUtils, Classes, AVL_Tree;
  30. // -------------------------------------------------------
  31. // DOMException
  32. // -------------------------------------------------------
  33. const
  34. // DOM Level 1 exception codes:
  35. INDEX_SIZE_ERR = 1; // index or size is negative, or greater than the allowed value
  36. DOMSTRING_SIZE_ERR = 2; // Specified range of text does not fit into a DOMString
  37. HIERARCHY_REQUEST_ERR = 3; // node is inserted somewhere it does not belong
  38. WRONG_DOCUMENT_ERR = 4; // node is used in a different document than the one that created it (that does not support it)
  39. INVALID_CHARACTER_ERR = 5; // invalid or illegal character is specified, such as in a name
  40. NO_DATA_ALLOWED_ERR = 6; // data is specified for a node which does not support data
  41. NO_MODIFICATION_ALLOWED_ERR = 7; // an attempt is made to modify an object where modifications are not allowed
  42. NOT_FOUND_ERR = 8; // an attempt is made to reference a node in a context where it does not exist
  43. NOT_SUPPORTED_ERR = 9; // implementation does not support the type of object requested
  44. INUSE_ATTRIBUTE_ERR = 10; // an attempt is made to add an attribute that is already in use elsewhere
  45. // DOM Level 2 exception codes:
  46. INVALID_STATE_ERR = 11; // an attempt is made to use an object that is not, or is no longer, usable
  47. SYNTAX_ERR = 12; // invalid or illegal string specified
  48. INVALID_MODIFICATION_ERR = 13; // an attempt is made to modify the type of the underlying object
  49. NAMESPACE_ERR = 14; // an attempt is made to create or change an object in a way which is incorrect with regard to namespaces
  50. INVALID_ACCESS_ERR = 15; // parameter or operation is not supported by the underlying object
  51. // -------------------------------------------------------
  52. // Node
  53. // -------------------------------------------------------
  54. const
  55. ELEMENT_NODE = 1;
  56. ATTRIBUTE_NODE = 2;
  57. TEXT_NODE = 3;
  58. CDATA_SECTION_NODE = 4;
  59. ENTITY_REFERENCE_NODE = 5;
  60. ENTITY_NODE = 6;
  61. PROCESSING_INSTRUCTION_NODE = 7;
  62. COMMENT_NODE = 8;
  63. DOCUMENT_NODE = 9;
  64. DOCUMENT_TYPE_NODE = 10;
  65. DOCUMENT_FRAGMENT_NODE = 11;
  66. NOTATION_NODE = 12;
  67. type
  68. TDOMImplementation = class;
  69. TDOMDocumentFragment = class;
  70. TDOMDocument = class;
  71. TDOMNode = class;
  72. TDOMNodeList = class;
  73. TDOMNamedNodeMap = class;
  74. TDOMCharacterData = class;
  75. TDOMAttr = class;
  76. TDOMElement = class;
  77. TDOMText = class;
  78. TDOMComment = class;
  79. TDOMCDATASection = class;
  80. TDOMDocumentType = class;
  81. TDOMNotation = class;
  82. TDOMEntity = class;
  83. TDOMEntityReference = class;
  84. TDOMProcessingInstruction = class;
  85. // -------------------------------------------------------
  86. // DOMString
  87. // -------------------------------------------------------
  88. DOMString = WideString;
  89. DOMPChar = PWideChar;
  90. EDOMError = class(Exception)
  91. public
  92. Code: Integer;
  93. constructor Create(ACode: Integer; const ASituation: String);
  94. end;
  95. EDOMIndexSize = class(EDOMError)
  96. public
  97. constructor Create(const ASituation: String);
  98. end;
  99. EDOMHierarchyRequest = class(EDOMError)
  100. public
  101. constructor Create(const ASituation: String);
  102. end;
  103. EDOMWrongDocument = class(EDOMError)
  104. public
  105. constructor Create(const ASituation: String);
  106. end;
  107. EDOMNotFound = class(EDOMError)
  108. public
  109. constructor Create(const ASituation: String);
  110. end;
  111. EDOMNotSupported = class(EDOMError)
  112. public
  113. constructor Create(const ASituation: String);
  114. end;
  115. EDOMInUseAttribute = class(EDOMError)
  116. public
  117. constructor Create(const ASituation: String);
  118. end;
  119. EDOMInvalidState = class(EDOMError)
  120. public
  121. constructor Create(const ASituation: String);
  122. end;
  123. EDOMSyntax = class(EDOMError)
  124. public
  125. constructor Create(const ASituation: String);
  126. end;
  127. EDOMInvalidModification = class(EDOMError)
  128. public
  129. constructor Create(const ASituation: String);
  130. end;
  131. EDOMNamespace = class(EDOMError)
  132. public
  133. constructor Create(const ASituation: String);
  134. end;
  135. EDOMInvalidAccess = class(EDOMError)
  136. public
  137. constructor Create(const ASituation: String);
  138. end;
  139. TRefClass = class
  140. protected
  141. RefCounter: LongInt;
  142. public
  143. constructor Create;
  144. function AddRef: LongInt; virtual;
  145. function Release: LongInt; virtual;
  146. end;
  147. { NodeType, NodeName and NodeValue had been moved from fields to functions.
  148. This lowers memory usage and also obsoletes most constructors,
  149. at a slight performance penalty. However, NodeName and NodeValue are
  150. accessible via fields using specialized properties of descendant classes,
  151. e.g. TDOMElement.TagName, TDOMCharacterData.Data etc.}
  152. TDOMNode = class
  153. protected
  154. FParentNode: TDOMNode;
  155. FPreviousSibling, FNextSibling: TDOMNode;
  156. FOwnerDocument: TDOMDocument;
  157. function GetNodeName: DOMString; virtual;
  158. function GetNodeValue: DOMString; virtual;
  159. procedure SetNodeValue(const AValue: DOMString); virtual;
  160. function GetFirstChild: TDOMNode; virtual;
  161. function GetLastChild: TDOMNode; virtual;
  162. function GetAttributes: TDOMNamedNodeMap; virtual;
  163. function GetRevision: Integer;
  164. function GetNodeType: Integer; virtual; abstract;
  165. function GetTextContent: DOMString; virtual;
  166. procedure SetTextContent(const AValue: DOMString); virtual;
  167. public
  168. constructor Create(AOwner: TDOMDocument);
  169. destructor Destroy; override;
  170. // Free NodeList with TDOMNodeList.Release!
  171. function GetChildNodes: TDOMNodeList;
  172. property NodeName: DOMString read GetNodeName;
  173. property NodeValue: DOMString read GetNodeValue write SetNodeValue;
  174. property NodeType: Integer read GetNodeType;
  175. property ParentNode: TDOMNode read FParentNode;
  176. property FirstChild: TDOMNode read GetFirstChild;
  177. property LastChild: TDOMNode read GetLastChild;
  178. property ChildNodes: TDOMNodeList read GetChildNodes;
  179. property PreviousSibling: TDOMNode read FPreviousSibling;
  180. property NextSibling: TDOMNode read FNextSibling;
  181. property Attributes: TDOMNamedNodeMap read GetAttributes;
  182. // DOM 2: is now nil for documents and unused DocTypes
  183. property OwnerDocument: TDOMDocument read FOwnerDocument;
  184. function InsertBefore(NewChild, RefChild: TDOMNode): TDOMNode; virtual;
  185. function ReplaceChild(NewChild, OldChild: TDOMNode): TDOMNode; virtual;
  186. function RemoveChild(OldChild: TDOMNode): TDOMNode; virtual;
  187. function AppendChild(NewChild: TDOMNode): TDOMNode; virtual;
  188. function HasChildNodes: Boolean; virtual;
  189. function CloneNode(deep: Boolean): TDOMNode; overload;
  190. // DOM level 2
  191. (*
  192. function Supports(const Feature, Version: DOMString): Boolean;
  193. *)
  194. function HasAttributes: Boolean; virtual;
  195. procedure Normalize;
  196. (*
  197. // TODO: What is that Java NULL for strings ???
  198. // always '' for nodes other than ELEMENT and ATTRIBUTE
  199. // as well as for nodes created with DOM 1 methods
  200. property NamespaceURI: DOMString read GetNamespaceURI;
  201. // Prefix may only be changed if it was specified at creation time.
  202. property Prefix: DOMString read FPrefix (write SetPrefix?);
  203. property LocalName: DOMString read FLocalName;
  204. *)
  205. // DOM level 3
  206. property TextContent: DOMString read GetTextContent write SetTextContent;
  207. // Extensions to DOM interface:
  208. function CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode; overload; virtual;
  209. function FindNode(const ANodeName: DOMString): TDOMNode; virtual;
  210. function CompareName(const name: DOMString): Integer; virtual;
  211. end;
  212. { The following class is an implementation specific extension, it is just an
  213. extended implementation of TDOMNode, the generic DOM::Node interface
  214. implementation. (Its main purpose is to save memory in a big node tree) }
  215. TDOMNode_WithChildren = class(TDOMNode)
  216. protected
  217. FFirstChild, FLastChild: TDOMNode;
  218. FChildNodeTree: TAVLTree;
  219. function GetFirstChild: TDOMNode; override;
  220. function GetLastChild: TDOMNode; override;
  221. procedure CloneChildren(ACopy: TDOMNode; ACloneOwner: TDOMDocument);
  222. procedure AddToChildNodeTree(NewNode: TDOMNode);
  223. procedure RemoveFromChildNodeTree(OldNode: TDOMNode);
  224. procedure FreeChildren;
  225. function GetTextContent: DOMString; override;
  226. procedure SetTextContent(const AValue: DOMString); override;
  227. function DoRemoveChild(OldChild: TDOMNode): TDOMNode;
  228. public
  229. destructor Destroy; override;
  230. function InsertBefore(NewChild, RefChild: TDOMNode): TDOMNode; override;
  231. function ReplaceChild(NewChild, OldChild: TDOMNode): TDOMNode; override;
  232. function RemoveChild(OldChild: TDOMNode): TDOMNode; override;
  233. function AppendChild(NewChild: TDOMNode): TDOMNode; override;
  234. function HasChildNodes: Boolean; override;
  235. function FindNode(const ANodeName: DOMString): TDOMNode; override;
  236. end;
  237. // -------------------------------------------------------
  238. // NodeList
  239. // -------------------------------------------------------
  240. TDOMNodeList = class(TRefClass)
  241. protected
  242. FNode: TDOMNode;
  243. FRevision: Integer;
  244. FList: TList;
  245. function GetCount: LongWord;
  246. function GetItem(index: LongWord): TDOMNode;
  247. procedure BuildList; virtual;
  248. public
  249. constructor Create(ANode: TDOMNode);
  250. destructor Destroy; override;
  251. property Item[index: LongWord]: TDOMNode read GetItem; default;
  252. property Count: LongWord read GetCount;
  253. end;
  254. { an extension to DOM interface, used to build recursive lists of elements }
  255. TDOMElementList = class(TDOMNodeList)
  256. protected
  257. filter: DOMString;
  258. FNamespaceFilter: DOMString;
  259. UseFilter: Boolean;
  260. procedure BuildList; override;
  261. public
  262. constructor Create(ANode: TDOMNode; const AFilter: DOMString); overload;
  263. constructor Create(ANode: TDOMNode; const nsURI, localName: DOMString); overload;
  264. end;
  265. // -------------------------------------------------------
  266. // NamedNodeMap
  267. // -------------------------------------------------------
  268. TDOMNamedNodeMap = class(TObject)
  269. protected
  270. FOwnerElement: TDOMNode;
  271. FNodeType: Integer;
  272. FList: TList;
  273. function GetItem(index: LongWord): TDOMNode;
  274. function GetLength: LongWord;
  275. function Find(const name: DOMString; out Index: LongWord): Boolean;
  276. function InternalRemove(const name: DOMString): TDOMNode;
  277. public
  278. constructor Create(AOwner: TDOMNode; ANodeType: Integer);
  279. destructor Destroy; override;
  280. function GetNamedItem(const name: DOMString): TDOMNode;
  281. function SetNamedItem(arg: TDOMNode): TDOMNode;
  282. function RemoveNamedItem(const name: DOMString): TDOMNode;
  283. // Introduced in DOM Level 2:
  284. function getNamedItemNS(const namespaceURI, localName: DOMString): TDOMNode;
  285. function setNamedItemNS(arg: TDOMNode): TDOMNode;
  286. function removeNamedItemNS(const namespaceURI,localName: DOMString): TDOMNode;
  287. // FIX: made readonly. Reason: Anyone was allowed to insert any node without any checking.
  288. property Item[index: LongWord]: TDOMNode read GetItem; default;
  289. property Length: LongWord read GetLength;
  290. end;
  291. // -------------------------------------------------------
  292. // CharacterData
  293. // -------------------------------------------------------
  294. TDOMCharacterData = class(TDOMNode)
  295. private
  296. FNodeValue: DOMString;
  297. protected
  298. function GetLength: LongWord;
  299. function GetNodeValue: DOMString; override;
  300. procedure SetNodeValue(const AValue: DOMString); override;
  301. public
  302. property Data: DOMString read FNodeValue write FNodeValue;
  303. property Length: LongWord read GetLength;
  304. function SubstringData(offset, count: LongWord): DOMString;
  305. procedure AppendData(const arg: DOMString);
  306. procedure InsertData(offset: LongWord; const arg: DOMString);
  307. procedure DeleteData(offset, count: LongWord);
  308. procedure ReplaceData(offset, count: LongWord; const arg: DOMString);
  309. end;
  310. // -------------------------------------------------------
  311. // DOMImplementation
  312. // -------------------------------------------------------
  313. TDOMImplementation = class
  314. public
  315. function HasFeature(const feature, version: DOMString): Boolean;
  316. // Introduced in DOM Level 2:
  317. function CreateDocumentType(const QualifiedName, PublicID,
  318. SystemID: DOMString): TDOMDocumentType;
  319. function CreateDocument(const NamespaceURI, QualifiedName: DOMString;
  320. doctype: TDOMDocumentType): TDOMDocument;
  321. end;
  322. // -------------------------------------------------------
  323. // DocumentFragment
  324. // -------------------------------------------------------
  325. TDOMDocumentFragment = class(TDOMNode_WithChildren)
  326. protected
  327. function GetNodeType: Integer; override;
  328. function GetNodeName: DOMString; override;
  329. end;
  330. // -------------------------------------------------------
  331. // Document
  332. // -------------------------------------------------------
  333. TDOMDocument = class(TDOMNode_WithChildren)
  334. protected
  335. FRevision: Integer;
  336. FImplementation: TDOMImplementation;
  337. function GetDocumentElement: TDOMElement;
  338. function GetDocType: TDOMDocumentType;
  339. function GetNodeType: Integer; override;
  340. function GetNodeName: DOMString; override;
  341. public
  342. property DocType: TDOMDocumentType read GetDocType;
  343. property Impl: TDOMImplementation read FImplementation;
  344. property DocumentElement: TDOMElement read GetDocumentElement;
  345. function CreateElement(const tagName: DOMString): TDOMElement; virtual;
  346. function CreateElementBuf(Buf: DOMPChar; Length: Integer): TDOMElement;
  347. function CreateDocumentFragment: TDOMDocumentFragment;
  348. function CreateTextNode(const data: DOMString): TDOMText;
  349. function CreateTextNodeBuf(Buf: DOMPChar; Length: Integer): TDOMText;
  350. function CreateComment(const data: DOMString): TDOMComment;
  351. function CreateCommentBuf(Buf: DOMPChar; Length: Integer): TDOMComment;
  352. function CreateCDATASection(const data: DOMString): TDOMCDATASection;
  353. virtual;
  354. function CreateProcessingInstruction(const target, data: DOMString):
  355. TDOMProcessingInstruction; virtual;
  356. function CreateAttribute(const name: DOMString): TDOMAttr;
  357. function CreateAttributeBuf(Buf: DOMPChar; Length: Integer): TDOMAttr;
  358. function CreateEntityReference(const name: DOMString): TDOMEntityReference;
  359. virtual;
  360. // Free NodeList with TDOMNodeList.Release!
  361. function GetElementsByTagName(const tagname: DOMString): TDOMNodeList;
  362. // DOM level 2 methods
  363. function ImportNode(ImportedNode: TDOMNode; Deep: Boolean): TDOMNode;
  364. function CreateElementNS(const NamespaceURI, QualifiedName: DOMString): TDOMElement;
  365. function CreateAttributeNS(const NamespaceURI, QualifiedName: DOMString): TDOMAttr;
  366. function GetElementsByTagNameNS(const namespaceURI, localName: DOMString): TDOMNodeList;
  367. function GetElementById(const ElementID: DOMString): TDOMElement;
  368. // Extensions to DOM interface:
  369. // TODO: obsolete now, but must check for usage dependencies
  370. constructor Create;
  371. end;
  372. TXMLDocument = class(TDOMDocument)
  373. public
  374. // These fields are extensions to the DOM interface:
  375. XMLVersion, Encoding, StylesheetType, StylesheetHRef: DOMString;
  376. function CreateCDATASection(const data: DOMString): TDOMCDATASection; override;
  377. function CreateProcessingInstruction(const target, data: DOMString):
  378. TDOMProcessingInstruction; override;
  379. function CreateEntityReference(const name: DOMString): TDOMEntityReference; override;
  380. end;
  381. // -------------------------------------------------------
  382. // Attr
  383. // -------------------------------------------------------
  384. TDOMAttr = class(TDOMNode_WithChildren)
  385. protected
  386. FName: DOMString;
  387. FSpecified: Boolean;
  388. FNormalize: Boolean;
  389. FOwnerElement: TDOMElement;
  390. function GetNodeValue: DOMString; override;
  391. function GetNodeType: Integer; override;
  392. function GetNodeName: DOMString; override;
  393. procedure SetNodeValue(const AValue: DOMString); override;
  394. public
  395. function CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode; overload; override;
  396. property Name: DOMString read FName;
  397. property Specified: Boolean read FSpecified;
  398. property Value: DOMString read GetNodeValue write SetNodeValue;
  399. // Introduced in DOM level 2:
  400. property OwnerElement: TDOMElement read FOwnerElement;
  401. // extensions
  402. function CompareName(const AName: DOMString): Integer; override;
  403. end;
  404. // -------------------------------------------------------
  405. // Element
  406. // -------------------------------------------------------
  407. TDOMElement = class(TDOMNode_WithChildren)
  408. protected
  409. FNodeName: DOMString;
  410. FAttributes: TDOMNamedNodeMap;
  411. function GetNodeType: Integer; override;
  412. function GetNodeName: DOMString; override;
  413. function GetAttributes: TDOMNamedNodeMap; override;
  414. public
  415. destructor Destroy; override;
  416. function CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode; overload; override;
  417. property TagName: DOMString read FNodeName;
  418. function GetAttribute(const name: DOMString): DOMString;
  419. procedure SetAttribute(const name, value: DOMString);
  420. procedure RemoveAttribute(const name: DOMString);
  421. function GetAttributeNode(const name: DOMString): TDOMAttr;
  422. function SetAttributeNode(NewAttr: TDOMAttr): TDOMAttr;
  423. function RemoveAttributeNode(OldAttr: TDOMAttr): TDOMAttr;
  424. // Free NodeList with TDOMNodeList.Release!
  425. function GetElementsByTagName(const name: DOMString): TDOMNodeList;
  426. // Introduced in DOM Level 2:
  427. function GetAttributeNS(const namespaceURI, localName: DOMString): DOMString;
  428. procedure SetAttributeNS(const namespaceURI, qualifiedName, value: DOMString);
  429. procedure RemoveAttributeNS(const namespaceURI, localName: DOMString);
  430. function GetAttributeNodeNS(const namespaceURI, localName: DOMString): TDOMAttr;
  431. function SetAttributeNodeNS(newAttr: TDOMAttr): TDOMAttr;
  432. function GetElementsByTagNameNS(const namespaceURI, localName: DOMString): TDOMNodeList;
  433. function hasAttribute(const name: DOMString): Boolean;
  434. function hasAttributeNS(const namespaceURI, localName: DOMString): Boolean;
  435. function HasAttributes: Boolean; override;
  436. // extension
  437. function CompareName(const name: DOMString): Integer; override;
  438. property AttribStrings[const Name: DOMString]: DOMString
  439. read GetAttribute write SetAttribute; default;
  440. end;
  441. // -------------------------------------------------------
  442. // Text
  443. // -------------------------------------------------------
  444. TDOMText = class(TDOMCharacterData)
  445. protected
  446. function GetNodeType: Integer; override;
  447. function GetNodeName: DOMString; override;
  448. public
  449. function CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode; overload; override;
  450. function SplitText(offset: LongWord): TDOMText;
  451. end;
  452. // -------------------------------------------------------
  453. // Comment
  454. // -------------------------------------------------------
  455. TDOMComment = class(TDOMCharacterData)
  456. protected
  457. function GetNodeType: Integer; override;
  458. function GetNodeName: DOMString; override;
  459. public
  460. function CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode; overload; override;
  461. end;
  462. // -------------------------------------------------------
  463. // CDATASection
  464. // -------------------------------------------------------
  465. TDOMCDATASection = class(TDOMText)
  466. protected
  467. function GetNodeType: Integer; override;
  468. function GetNodeName: DOMString; override;
  469. public
  470. function CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode; overload; override;
  471. end;
  472. // -------------------------------------------------------
  473. // DocumentType
  474. // -------------------------------------------------------
  475. TDOMDocumentType = class(TDOMNode)
  476. protected
  477. FName: DOMString;
  478. FPublicID: DOMString;
  479. FSystemID: DOMString;
  480. FInternalSubset: DOMString;
  481. FEntities, FNotations: TDOMNamedNodeMap;
  482. function GetEntities: TDOMNamedNodeMap;
  483. function GetNotations: TDOMNamedNodeMap;
  484. function GetNodeType: Integer; override;
  485. function GetNodeName: DOMString; override;
  486. public
  487. destructor Destroy; override;
  488. function CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode; overload; override;
  489. property Name: DOMString read FName;
  490. property Entities: TDOMNamedNodeMap read GetEntities;
  491. property Notations: TDOMNamedNodeMap read GetNotations;
  492. // Introduced in DOM Level 2:
  493. property PublicID: DOMString read FPublicID;
  494. property SystemID: DOMString read FSystemID;
  495. property InternalSubset: DOMString read FInternalSubset;
  496. end;
  497. // -------------------------------------------------------
  498. // Notation
  499. // -------------------------------------------------------
  500. TDOMNotation = class(TDOMNode)
  501. protected
  502. FName: DOMString;
  503. FPublicID, FSystemID: DOMString;
  504. function GetNodeType: Integer; override;
  505. function GetNodeName: DOMString; override;
  506. public
  507. function CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode; overload; override;
  508. property PublicID: DOMString read FPublicID;
  509. property SystemID: DOMString read FSystemID;
  510. end;
  511. // -------------------------------------------------------
  512. // Entity
  513. // -------------------------------------------------------
  514. TDOMEntity = class(TDOMNode_WithChildren)
  515. protected
  516. FName: DOMString;
  517. FPublicID, FSystemID, FNotationName: DOMString;
  518. function GetNodeType: Integer; override;
  519. function GetNodeName: DOMString; override;
  520. public
  521. property PublicID: DOMString read FPublicID;
  522. property SystemID: DOMString read FSystemID;
  523. property NotationName: DOMString read FNotationName;
  524. end;
  525. // -------------------------------------------------------
  526. // EntityReference
  527. // -------------------------------------------------------
  528. TDOMEntityReference = class(TDOMNode_WithChildren)
  529. protected
  530. FName: DOMString;
  531. function GetNodeType: Integer; override;
  532. function GetNodeName: DOMString; override;
  533. public
  534. function CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode; overload; override;
  535. end;
  536. // -------------------------------------------------------
  537. // ProcessingInstruction
  538. // -------------------------------------------------------
  539. TDOMProcessingInstruction = class(TDOMNode)
  540. private
  541. FTarget: DOMString;
  542. FNodeValue: DOMString;
  543. protected
  544. function GetNodeType: Integer; override;
  545. function GetNodeName: DOMString; override;
  546. function GetNodeValue: DOMString; override;
  547. procedure SetNodeValue(const AValue: DOMString); override;
  548. public
  549. function CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode; overload; override;
  550. property Target: DOMString read FTarget;
  551. property Data: DOMString read FNodeValue write FNodeValue;
  552. end;
  553. // =======================================================
  554. // =======================================================
  555. implementation
  556. constructor TRefClass.Create;
  557. begin
  558. inherited Create;
  559. RefCounter := 1;
  560. end;
  561. function TRefClass.AddRef: LongInt;
  562. begin
  563. Inc(RefCounter);
  564. Result := RefCounter;
  565. end;
  566. function TRefClass.Release: LongInt;
  567. begin
  568. Dec(RefCounter);
  569. Result := RefCounter;
  570. if RefCounter <= 0 then Free;
  571. end;
  572. // -------------------------------------------------------
  573. // DOM Exception
  574. // -------------------------------------------------------
  575. constructor EDOMError.Create(ACode: Integer; const ASituation: String);
  576. begin
  577. Code := ACode;
  578. inherited Create(Self.ClassName + ' in ' + ASituation);
  579. end;
  580. constructor EDOMIndexSize.Create(const ASituation: String); // 1
  581. begin
  582. inherited Create(INDEX_SIZE_ERR, ASituation);
  583. end;
  584. constructor EDOMHierarchyRequest.Create(const ASituation: String); // 3
  585. begin
  586. inherited Create(HIERARCHY_REQUEST_ERR, ASituation);
  587. end;
  588. constructor EDOMWrongDocument.Create(const ASituation: String); // 4
  589. begin
  590. inherited Create(WRONG_DOCUMENT_ERR, ASituation);
  591. end;
  592. constructor EDOMNotFound.Create(const ASituation: String); // 8
  593. begin
  594. inherited Create(NOT_FOUND_ERR, ASituation);
  595. end;
  596. constructor EDOMNotSupported.Create(const ASituation: String); // 9
  597. begin
  598. inherited Create(NOT_SUPPORTED_ERR, ASituation);
  599. end;
  600. constructor EDOMInUseAttribute.Create(const ASituation: String); // 10
  601. begin
  602. inherited Create(INUSE_ATTRIBUTE_ERR, ASituation);
  603. end;
  604. constructor EDOMInvalidState.Create(const ASituation: String); // 11
  605. begin
  606. inherited Create(INVALID_STATE_ERR, ASituation);
  607. end;
  608. constructor EDOMSyntax.Create(const ASituation: String); // 12
  609. begin
  610. inherited Create(SYNTAX_ERR, ASituation);
  611. end;
  612. constructor EDOMInvalidModification.Create(const ASituation: String); // 13
  613. begin
  614. inherited Create(INVALID_MODIFICATION_ERR, ASituation);
  615. end;
  616. constructor EDOMNamespace.Create(const ASituation: String); // 14
  617. begin
  618. inherited Create(NAMESPACE_ERR, ASituation);
  619. end;
  620. constructor EDOMInvalidAccess.Create(const ASituation: String); // 15
  621. begin
  622. inherited Create(INVALID_ACCESS_ERR, ASituation);
  623. end;
  624. // -------------------------------------------------------
  625. // Node
  626. // -------------------------------------------------------
  627. constructor TDOMNode.Create(AOwner: TDOMDocument);
  628. begin
  629. FOwnerDocument := AOwner;
  630. inherited Create;
  631. end;
  632. destructor TDOMNode.Destroy;
  633. begin
  634. if Assigned(FParentNode) and FParentNode.InheritsFrom(TDOMNode_WithChildren) then
  635. TDOMNode_WithChildren(FParentNode).DoRemoveChild(Self);
  636. inherited Destroy;
  637. end;
  638. function TDOMNode.GetNodeName: DOMString;
  639. begin
  640. Result := '';
  641. end;
  642. function TDOMNode.GetNodeValue: DOMString;
  643. begin
  644. Result := '';
  645. end;
  646. procedure TDOMNode.SetNodeValue(const AValue: DOMString);
  647. begin
  648. // do nothing
  649. end;
  650. function TDOMNode.GetChildNodes: TDOMNodeList;
  651. begin
  652. Result := TDOMNodeList.Create(Self);
  653. end;
  654. function TDOMNode.GetFirstChild: TDOMNode;
  655. begin
  656. Result := nil;
  657. end;
  658. function TDOMNode.GetLastChild: TDOMNode;
  659. begin
  660. Result := nil;
  661. end;
  662. function TDOMNode.GetAttributes: TDOMNamedNodeMap;
  663. begin
  664. Result := nil;
  665. end;
  666. function TDOMNode.InsertBefore(NewChild, RefChild: TDOMNode): TDOMNode;
  667. begin
  668. raise EDOMHierarchyRequest.Create('Node.InsertBefore');
  669. Result:=nil;
  670. end;
  671. function TDOMNode.ReplaceChild(NewChild, OldChild: TDOMNode): TDOMNode;
  672. begin
  673. raise EDOMHierarchyRequest.Create('Node.ReplaceChild');
  674. Result:=nil;
  675. end;
  676. function TDOMNode.RemoveChild(OldChild: TDOMNode): TDOMNode;
  677. begin
  678. // OldChild isn't in our child list
  679. raise EDOMNotFound.Create('Node.RemoveChild');
  680. Result:=nil;
  681. end;
  682. function TDOMNode.AppendChild(NewChild: TDOMNode): TDOMNode;
  683. begin
  684. raise EDOMHierarchyRequest.Create('Node.AppendChild');
  685. Result:=nil;
  686. end;
  687. function TDOMNode.HasChildNodes: Boolean;
  688. begin
  689. Result := False;
  690. end;
  691. function TDOMNode.CloneNode(deep: Boolean): TDOMNode;
  692. begin
  693. Result := CloneNode(deep, FOwnerDocument);
  694. end;
  695. function TDOMNode.CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode;
  696. begin
  697. raise EDOMNotSupported.CreateFmt('CloneNode not implemented for %s', [ClassName]);
  698. Result:=nil;
  699. end;
  700. function TDOMNode.FindNode(const ANodeName: DOMString): TDOMNode;
  701. begin
  702. // FIX: we have no children, hence cannot find anything
  703. Result := nil;
  704. end;
  705. function TDOMNode.GetRevision: Integer;
  706. begin
  707. Result := FOwnerDocument.FRevision;
  708. end;
  709. function TDOMNode.HasAttributes: Boolean;
  710. begin
  711. Result := False;
  712. end;
  713. // DONE: moved to TDOMNode and implemented
  714. procedure TDOMNode.Normalize;
  715. var
  716. Child, tmp: TDOMNode;
  717. Txt: TDOMText;
  718. begin
  719. Child := FirstChild;
  720. Txt := nil;
  721. while Assigned(Child) do
  722. begin
  723. if Child.NodeType = TEXT_NODE then
  724. begin
  725. if Assigned(Txt) then
  726. begin
  727. tmp := Child.NextSibling;
  728. Txt.AppendData(Child.nodeValue);
  729. RemoveChild(Child);
  730. Child := tmp;
  731. end
  732. else
  733. begin
  734. Txt := TDOMText(Child);
  735. Child := Child.NextSibling;
  736. end
  737. end
  738. else
  739. begin
  740. Child.Normalize; // should be recursive!
  741. Child := Child.NextSibling;
  742. Txt := nil;
  743. end;
  744. end;
  745. end;
  746. function TDOMNode.GetTextContent: DOMString;
  747. begin
  748. Result := NodeValue;
  749. end;
  750. procedure TDOMNode.SetTextContent(const AValue: DOMString);
  751. begin
  752. NodeValue := AValue;
  753. end;
  754. function CompareDOMStrings(const s1, s2: DOMPChar; l1, l2: integer): integer;
  755. var i: integer;
  756. begin
  757. Result:=l1-l2;
  758. i:=0;
  759. while (i<l1) and (Result=0) do begin
  760. Result:=ord(s1[i])-ord(s2[i]);
  761. inc(i);
  762. end;
  763. end;
  764. // generic version (slow)
  765. function TDOMNode.CompareName(const name: DOMString): Integer;
  766. var
  767. SelfName: DOMString;
  768. begin
  769. SelfName := NodeName;
  770. Result := CompareDOMStrings(DOMPChar(name), DOMPChar(SelfName), Length(name), Length(SelfName));
  771. end;
  772. //------------------------------------------------------------------------------
  773. function CompareDOMNodeWithDOMNode(Node1, Node2: Pointer): integer;
  774. begin
  775. Result:=CompareDOMStrings(DOMPChar(TDOMNode(Node1).NodeName),
  776. DOMPChar(TDOMNode(Node2).NodeName),
  777. length(TDOMNode(Node1).NodeName),
  778. length(TDOMNode(Node2).NodeName)
  779. );
  780. end;
  781. function CompareDOMStringWithDOMNode(AKey, ANode: Pointer): integer;
  782. begin
  783. Result := TDOMNode(ANode).CompareName(DOMString(AKey));
  784. end;
  785. function TDOMNode_WithChildren.GetFirstChild: TDOMNode;
  786. begin
  787. Result := FFirstChild;
  788. end;
  789. function TDOMNode_WithChildren.GetLastChild: TDOMNode;
  790. begin
  791. Result := FLastChild;
  792. end;
  793. destructor TDOMNode_WithChildren.Destroy;
  794. begin
  795. FreeAndNil(FChildNodeTree);
  796. FreeChildren;
  797. inherited Destroy;
  798. end;
  799. function TDOMNode_WithChildren.InsertBefore(NewChild, RefChild: TDOMNode):
  800. TDOMNode;
  801. var
  802. Tmp: TDOMNode;
  803. begin
  804. Result := NewChild;
  805. if not Assigned(RefChild) then
  806. begin
  807. AppendChild(NewChild);
  808. exit;
  809. end;
  810. if NewChild.FOwnerDocument <> FOwnerDocument then
  811. raise EDOMWrongDocument.Create('NodeWC.InsertBefore');
  812. if RefChild.ParentNode <> Self then
  813. raise EDOMHierarchyRequest.Create('NodeWC.InsertBefore');
  814. Inc(FOwnerDocument.FRevision); // invalidate nodelists
  815. // ugly workaround for RemoveChild issue...
  816. if Assigned(NewChild.FParentNode) then
  817. if NewChild.FParentNode.InheritsFrom(TDOMNode_WithChildren) then
  818. TDOMNode_WithChildren(NewChild.FParentNode).DoRemoveChild(NewChild);
  819. // DONE: Implemented InsertBefore for DocumentFragments (except ChildNodeTree)
  820. if NewChild.NodeType = DOCUMENT_FRAGMENT_NODE then
  821. begin
  822. // Is fragment empty?
  823. Tmp := NewChild.FirstChild;
  824. if not Assigned(Tmp) then
  825. Exit;
  826. // reparent nodes
  827. while Assigned(Tmp) do
  828. begin
  829. Tmp.FParentNode := Self;
  830. Tmp := Tmp.NextSibling;
  831. end;
  832. // won't get here if RefChild = nil...
  833. if (RefChild = nil) or (RefChild.FPreviousSibling = nil) then
  834. begin // insert at the beginning <- AppendChild ??? ->
  835. // no, AppendChild will insert after RefChild and we need it before
  836. if Assigned(FirstChild) then
  837. FirstChild.FPreviousSibling := NewChild.LastChild;
  838. NewChild.LastChild.FNextSibling := FirstChild;
  839. if not Assigned(FLastChild) then
  840. FLastChild := NewChild.LastChild;
  841. FFirstChild := NewChild.FirstChild;
  842. end
  843. else // insert to the middle
  844. begin
  845. NewChild.LastChild.FNextSibling := RefChild;
  846. NewChild.FirstChild.FPreviousSibling := RefChild.FPreviousSibling;
  847. RefChild.FPreviousSibling.FNextSibling := NewChild.FirstChild;
  848. RefChild.FPreviousSibling := NewChild.LastChild;
  849. end;
  850. // finally, detach nodes from the fragment
  851. TDOMDocumentFragment(NewChild).FFirstChild := nil;
  852. TDOMDocumentFragment(NewChild).FLastChild := nil;
  853. // TODO: ChildNodeTree...
  854. Exit;
  855. end;
  856. NewChild.FNextSibling := RefChild;
  857. if RefChild = FFirstChild then
  858. FFirstChild := NewChild
  859. else
  860. begin
  861. RefChild.FPreviousSibling.FNextSibling := NewChild;
  862. NewChild.FPreviousSibling := RefChild.FPreviousSibling;
  863. end;
  864. RefChild.FPreviousSibling := NewChild;
  865. NewChild.FParentNode := Self;
  866. AddToChildNodeTree(NewChild);
  867. end;
  868. function TDOMNode_WithChildren.ReplaceChild(NewChild, OldChild: TDOMNode):
  869. TDOMNode;
  870. begin
  871. // Inc(FOwnerDocument.FRevision); // invalidate nodelists (will happen anyway)
  872. RemoveFromChildNodeTree(OldChild);
  873. InsertBefore(NewChild, OldChild);
  874. if Assigned(OldChild) then
  875. RemoveChild(OldChild);
  876. // TODO: must return OldChild, if I understand that right...
  877. // but OldChild is destroyed!
  878. Result := NewChild;
  879. end;
  880. function TDOMNode_WithChildren.DoRemoveChild(OldChild: TDOMNode): TDOMNode;
  881. begin
  882. if OldChild.ParentNode <> Self then
  883. raise EDOMNotFound.Create('NodeWC.RemoveChild');
  884. Inc(FOwnerDocument.FRevision); // invalidate nodelists
  885. if OldChild = FFirstChild then
  886. FFirstChild := FFirstChild.FNextSibling
  887. else
  888. OldChild.FPreviousSibling.FNextSibling := OldChild.FNextSibling;
  889. if OldChild = FLastChild then
  890. FLastChild := FLastChild.FPreviousSibling
  891. else
  892. OldChild.FNextSibling.FPreviousSibling := OldChild.FPreviousSibling;
  893. RemoveFromChildNodeTree(OldChild);
  894. // Make sure removed child does not contain references to nowhere
  895. OldChild.FPreviousSibling := nil;
  896. OldChild.FNextSibling := nil;
  897. OldChild.FParentNode := nil;
  898. Result := OldChild;
  899. end;
  900. function TDOMNode_WithChildren.RemoveChild(OldChild: TDOMNode):
  901. TDOMNode;
  902. begin
  903. DoRemoveChild(OldChild);
  904. // DOM level 2: Must return removed node
  905. OldChild.Free;
  906. Result:=nil;
  907. end;
  908. function TDOMNode_WithChildren.AppendChild(NewChild: TDOMNode): TDOMNode;
  909. var
  910. Tmp: TDOMNode;
  911. begin
  912. if NewChild.FOwnerDocument <> FOwnerDocument then
  913. raise EDOMWrongDocument.Create('NodeWC.AppendChild');
  914. Tmp := Self;
  915. while Assigned(Tmp) do
  916. begin
  917. if Tmp = NewChild then
  918. raise EDOMHierarchyRequest.Create('NodeWC.AppendChild (cycle in tree)');
  919. Tmp := Tmp.ParentNode;
  920. end;
  921. Inc(FOwnerDocument.FRevision); // invalidate nodelists
  922. // TODO: RemoveChild destroys removed node -> CRASH
  923. // this is a very ugly workaround...
  924. if Assigned(NewChild.FParentNode) then
  925. if NewChild.FParentNode.InheritsFrom(TDOMNode_WithChildren) then
  926. TDOMNode_WithChildren(NewChild.FParentNode).DoRemoveChild(NewChild);
  927. // DONE: supported AppendChild for DocumentFragments (except ChildNodeTree)
  928. if NewChild.NodeType = DOCUMENT_FRAGMENT_NODE then
  929. begin
  930. Tmp := NewChild.FirstChild;
  931. // Is fragment empty?
  932. if Assigned(Tmp) then
  933. begin
  934. // reparent nodes
  935. while Assigned(Tmp) do
  936. begin
  937. Tmp.FParentNode := Self;
  938. Tmp := Tmp.NextSibling;
  939. end;
  940. if Assigned(FLastChild) then
  941. FLastChild.FNextSibling := NewChild.FirstChild;
  942. NewChild.FirstChild.FPreviousSibling := LastChild;
  943. if not Assigned(FFirstChild) then
  944. FFirstChild := NewChild.FirstChild;
  945. FLastChild := NewChild.LastChild;
  946. // detach nodes from fragment
  947. TDOMDocumentFragment(NewChild).FFirstChild := nil;
  948. TDOMDocumentFragment(NewChild).FLastChild := nil;
  949. // TODO: ChildNodeTree...
  950. end;
  951. end
  952. else
  953. begin
  954. if Assigned(FFirstChild) then
  955. begin
  956. FLastChild.FNextSibling := NewChild;
  957. NewChild.FPreviousSibling := FLastChild;
  958. end else
  959. FFirstChild := NewChild;
  960. FLastChild := NewChild;
  961. NewChild.FParentNode := Self;
  962. AddToChildNodeTree(NewChild);
  963. end;
  964. Result := NewChild;
  965. end;
  966. function TDOMNode_WithChildren.HasChildNodes: Boolean;
  967. begin
  968. Result := Assigned(FFirstChild);
  969. end;
  970. function TDOMNode_WithChildren.FindNode(const ANodeName: DOMString): TDOMNode;
  971. var AVLNode: TAVLTreeNode;
  972. begin
  973. Result:=nil;
  974. if FChildNodeTree<>nil then begin
  975. AVLNode:=FChildNodeTree.FindKey(DOMPChar(ANodeName),
  976. @CompareDOMStringWithDOMNode);
  977. if AVLNode<>nil then
  978. Result:=TDOMNode(AVLNode.Data);
  979. end;
  980. end;
  981. procedure TDOMNode_WithChildren.CloneChildren(ACopy: TDOMNode;
  982. ACloneOwner: TDOMDocument);
  983. var
  984. node: TDOMNode;
  985. begin
  986. node := FirstChild;
  987. while Assigned(node) do
  988. begin
  989. ACopy.AppendChild(node.CloneNode(True, ACloneOwner));
  990. node := node.NextSibling;
  991. end;
  992. end;
  993. procedure TDOMNode_WithChildren.FreeChildren;
  994. var
  995. child, next: TDOMNode;
  996. begin
  997. child := FFirstChild;
  998. while Assigned(child) do
  999. begin
  1000. next := child.NextSibling;
  1001. child.FParentNode := nil;
  1002. child.Free;
  1003. child := next;
  1004. end;
  1005. FFirstChild := nil;
  1006. FLastChild := nil;
  1007. end;
  1008. function TDOMNode_WithChildren.GetTextContent: DOMString;
  1009. var
  1010. child: TDOMNode;
  1011. begin
  1012. Result := '';
  1013. child := FFirstChild;
  1014. // TODO: probably very slow, optimization needed
  1015. // TODO: must ignore whitespace nodes
  1016. while Assigned(child) do
  1017. begin
  1018. if not (child.NodeType in [COMMENT_NODE, PROCESSING_INSTRUCTION_NODE]) then
  1019. Result := Result + child.TextContent;
  1020. child := child.NextSibling;
  1021. end;
  1022. end;
  1023. procedure TDOMNode_WithChildren.SetTextContent(const AValue: DOMString);
  1024. begin
  1025. FreeChildren;
  1026. if AValue <> '' then
  1027. AppendChild(FOwnerDocument.CreateTextNode(AValue));
  1028. end;
  1029. procedure TDOMNode_WithChildren.AddToChildNodeTree(NewNode: TDOMNode);
  1030. begin
  1031. if FChildNodeTree=nil then
  1032. FChildNodeTree:=TAVLTree.Create(@CompareDOMNodeWithDOMNode);
  1033. if FChildNodeTree.Find(NewNode)=nil then
  1034. FChildNodeTree.Add(NewNode);
  1035. end;
  1036. procedure TDOMNode_WithChildren.RemoveFromChildNodeTree(OldNode: TDOMNode);
  1037. begin
  1038. if FChildNodeTree<>nil then
  1039. FChildNodeTree.Remove(OldNode);
  1040. end;
  1041. // -------------------------------------------------------
  1042. // NodeList
  1043. // -------------------------------------------------------
  1044. constructor TDOMNodeList.Create(ANode: TDOMNode);
  1045. begin
  1046. inherited Create;
  1047. FNode := ANode;
  1048. FRevision := ANode.GetRevision-1; // force BuildList at first access
  1049. FList := TList.Create;
  1050. end;
  1051. destructor TDOMNodeList.Destroy;
  1052. begin
  1053. FList.Free;
  1054. inherited Destroy;
  1055. end;
  1056. procedure TDOMNodeList.BuildList;
  1057. var
  1058. Child: TDOMNode;
  1059. begin
  1060. FList.Clear;
  1061. FRevision := FNode.GetRevision; // refresh
  1062. Child := FNode.FirstChild;
  1063. while Assigned(Child) do
  1064. begin
  1065. FList.Add(Child);
  1066. Child := Child.NextSibling;
  1067. end;
  1068. end;
  1069. function TDOMNodeList.GetCount: LongWord;
  1070. begin
  1071. if FRevision <> FNode.GetRevision then
  1072. BuildList;
  1073. Result := FList.Count;
  1074. end;
  1075. function TDOMNodeList.GetItem(index: LongWord): TDOMNode;
  1076. begin
  1077. if FRevision <> FNode.GetRevision then
  1078. BuildList;
  1079. if index < LongWord(FList.Count) then
  1080. Result := TDOMNode(FList[index])
  1081. else
  1082. Result := nil;
  1083. end;
  1084. { TDOMElementList }
  1085. constructor TDOMElementList.Create(ANode: TDOMNode; const AFilter: DOMString);
  1086. begin
  1087. inherited Create(ANode);
  1088. filter := AFilter;
  1089. UseFilter := filter <> '*';
  1090. end;
  1091. constructor TDOMElementList.Create(ANode: TDOMNode; const nsURI, localName: DOMString);
  1092. begin
  1093. inherited Create(ANode);
  1094. filter := localName;
  1095. FNamespaceFilter := nsURI;
  1096. UseFilter := (filter <> '*') and (FNamespaceFilter <> '*');
  1097. end;
  1098. // TODO: namespace support here
  1099. procedure TDOMElementList.BuildList;
  1100. var
  1101. Child: TDOMNode;
  1102. begin
  1103. FList.Clear;
  1104. FRevision := FNode.GetRevision; // refresh
  1105. Child := FNode.FirstChild;
  1106. while Assigned(Child) and (Child <> FNode) do
  1107. begin
  1108. if (Child.NodeType = ELEMENT_NODE) and (not UseFilter or (TDOMElement(Child).TagName = filter)) then
  1109. FList.Add(Child);
  1110. // recursive track node hierarchy
  1111. if Assigned(Child.FirstChild) then
  1112. Child := Child.FirstChild
  1113. else
  1114. if Assigned(Child.NextSibling) then
  1115. Child := Child.NextSibling
  1116. else
  1117. begin
  1118. Child := Child.ParentNode;
  1119. while Assigned(Child) and (Child <> FNode) and not Assigned(Child.NextSibling) do
  1120. Child := Child.ParentNode;
  1121. if Assigned(Child) and (Child <> FNode) then
  1122. Child := Child.NextSibling;
  1123. end;
  1124. end;
  1125. end;
  1126. // -------------------------------------------------------
  1127. // NamedNodeMap
  1128. // -------------------------------------------------------
  1129. constructor TDOMNamedNodeMap.Create(AOwner: TDOMNode; ANodeType: Integer);
  1130. begin
  1131. inherited Create;
  1132. FOwnerElement := AOwner;
  1133. FNodeType := ANodeType;
  1134. FList := TList.Create;
  1135. end;
  1136. destructor TDOMNamedNodeMap.Destroy;
  1137. var
  1138. I: Integer;
  1139. begin
  1140. for I := FList.Count-1 downto 0 do
  1141. TDOMNode(FList[I]).Free;
  1142. FList.Free;
  1143. inherited Destroy;
  1144. end;
  1145. function TDOMNamedNodeMap.GetItem(index: LongWord): TDOMNode;
  1146. begin
  1147. if index < LongWord(FList.Count) then
  1148. Result := TDOMNode(FList.List^[index])
  1149. else
  1150. Result := nil;
  1151. end;
  1152. function TDOMNamedNodeMap.GetLength: LongWord;
  1153. begin
  1154. Result := FList.Count;
  1155. end;
  1156. function TDOMNamedNodeMap.Find(const name: DOMString; out Index: LongWord): Boolean;
  1157. var
  1158. L, H, I, C: Integer;
  1159. begin
  1160. Result := False;
  1161. L := 0;
  1162. H := FList.Count - 1;
  1163. while L <= H do
  1164. begin
  1165. I := (L + H) shr 1;
  1166. C := TDOMNode(FList.List^[I]).CompareName(name);
  1167. if C > 0 then L := I + 1 else
  1168. begin
  1169. H := I - 1;
  1170. if C = 0 then
  1171. begin
  1172. Result := True;
  1173. L := I;
  1174. end;
  1175. end;
  1176. end;
  1177. Index := L;
  1178. end;
  1179. function TDOMNamedNodeMap.GetNamedItem(const name: DOMString): TDOMNode;
  1180. var
  1181. i: Cardinal;
  1182. begin
  1183. if Find(name, i) then
  1184. Result := TDOMNode(FList.List^[i])
  1185. else
  1186. Result := nil;
  1187. end;
  1188. function TDOMNamedNodeMap.GetNamedItemNS(const namespaceURI, localName: DOMString): TDOMNode;
  1189. begin
  1190. // TODO: implement TDOMNamedNodeMap.GetNamedItemNS
  1191. raise EDOMNotSupported.Create('TDOMNamedNodeMap.GetNamedItemNS');
  1192. Result := nil;
  1193. end;
  1194. function TDOMNamedNodeMap.SetNamedItem(arg: TDOMNode): TDOMNode;
  1195. var
  1196. i: Cardinal;
  1197. AttrOwner: TDOMElement;
  1198. Exists: Boolean;
  1199. begin
  1200. if arg.FOwnerDocument <> FOwnerElement.FOwnerDocument then
  1201. raise EDOMWrongDocument.Create('NamedNodeMap.SetNamedItem');
  1202. if arg.NodeType <> FNodeType then
  1203. raise EDOMHierarchyRequest.Create('NamedNodeMap.SetNamedItem');
  1204. if FNodeType = ATTRIBUTE_NODE then
  1205. begin
  1206. AttrOwner := TDOMAttr(arg).ownerElement;
  1207. if Assigned(AttrOwner) and (AttrOwner <> FOwnerElement) then
  1208. raise EDOMInUseAttribute.Create('NamedNodeMap.SetNamedItem');
  1209. TDOMAttr(arg).FOwnerElement := TDOMElement(FOwnerElement);
  1210. Exists := Find(TDOMAttr(arg).FName, i); // optimization
  1211. end
  1212. else
  1213. Exists := Find(arg.NodeName, i);
  1214. if Exists then
  1215. begin
  1216. Result := TDOMNode(FList.List^[i]);
  1217. FList.List^[i] := arg;
  1218. exit;
  1219. end;
  1220. FList.Insert(i, arg);
  1221. Result := nil;
  1222. end;
  1223. function TDOMNamedNodeMap.SetNamedItemNS(arg: TDOMNode): TDOMNode;
  1224. begin
  1225. // TODO: implement TDOMNamedNodeMap.SetNamedItemNS
  1226. Result := nil;
  1227. end;
  1228. function TDOMNamedNodeMap.InternalRemove(const name: DOMString): TDOMNode;
  1229. var
  1230. i: Cardinal;
  1231. begin
  1232. Result := nil;
  1233. if Find(name, i) then
  1234. begin
  1235. Result := TDOMNode(FList.List^[i]);
  1236. FList.Delete(I);
  1237. if Result.NodeType = ATTRIBUTE_NODE then
  1238. TDOMAttr(Result).FOwnerElement := nil;
  1239. end;
  1240. end;
  1241. function TDOMNamedNodeMap.RemoveNamedItem(const name: DOMString): TDOMNode;
  1242. begin
  1243. Result := InternalRemove(name);
  1244. if Result = nil then
  1245. raise EDOMNotFound.Create('NamedNodeMap.RemoveNamedItem');
  1246. end;
  1247. function TDOMNamedNodeMap.RemoveNamedItemNS(const namespaceURI, localName: DOMString): TDOMNode;
  1248. begin
  1249. // TODO: Implement TDOMNamedNodeMap.RemoveNamedItemNS
  1250. Result := nil;
  1251. end;
  1252. // -------------------------------------------------------
  1253. // CharacterData
  1254. // -------------------------------------------------------
  1255. function TDOMCharacterData.GetLength: LongWord;
  1256. begin
  1257. Result := system.Length(FNodeValue);
  1258. end;
  1259. function TDOMCharacterData.GetNodeValue: DOMString;
  1260. begin
  1261. Result := FNodeValue;
  1262. end;
  1263. procedure TDOMCharacterData.SetNodeValue(const AValue: DOMString);
  1264. begin
  1265. FNodeValue := AValue;
  1266. end;
  1267. function TDOMCharacterData.SubstringData(offset, count: LongWord): DOMString;
  1268. begin
  1269. if (offset > Length) then
  1270. raise EDOMIndexSize.Create('CharacterData.SubstringData');
  1271. Result := Copy(FNodeValue, offset + 1, count);
  1272. end;
  1273. procedure TDOMCharacterData.AppendData(const arg: DOMString);
  1274. begin
  1275. FNodeValue := FNodeValue + arg;
  1276. end;
  1277. procedure TDOMCharacterData.InsertData(offset: LongWord; const arg: DOMString);
  1278. begin
  1279. if (offset > Length) then
  1280. raise EDOMIndexSize.Create('CharacterData.InsertData');
  1281. // TODO: use System.Insert?
  1282. FNodeValue := Copy(FNodeValue, 1, offset) + arg +
  1283. Copy(FNodeValue, offset + 1, Length);
  1284. end;
  1285. procedure TDOMCharacterData.DeleteData(offset, count: LongWord);
  1286. begin
  1287. if (offset > Length) then
  1288. raise EDOMIndexSize.Create('CharacterData.DeleteData');
  1289. // TODO: use System.Delete?
  1290. FNodeValue := Copy(FNodeValue, 1, offset) +
  1291. Copy(FNodeValue, offset + count + 1, Length);
  1292. end;
  1293. procedure TDOMCharacterData.ReplaceData(offset, count: LongWord; const arg: DOMString);
  1294. begin
  1295. DeleteData(offset, count);
  1296. InsertData(offset, arg);
  1297. end;
  1298. // -------------------------------------------------------
  1299. // DocumentFragmet
  1300. // -------------------------------------------------------
  1301. function TDOMDocumentFragment.GetNodeType: Integer;
  1302. begin
  1303. Result := DOCUMENT_FRAGMENT_NODE;
  1304. end;
  1305. function TDOMDocumentFragment.GetNodeName: DOMString;
  1306. begin
  1307. Result := '#document-fragment';
  1308. end;
  1309. // -------------------------------------------------------
  1310. // DOMImplementation
  1311. // -------------------------------------------------------
  1312. function TDOMImplementation.HasFeature(const feature, version: DOMString):
  1313. Boolean;
  1314. begin
  1315. // very basic
  1316. if (feature = 'XML') then
  1317. begin
  1318. if (version = '') or (version = '1.0') then
  1319. Result := True
  1320. else
  1321. Result := False;
  1322. end
  1323. else
  1324. Result := False;
  1325. end;
  1326. function TDOMImplementation.CreateDocumentType(const QualifiedName, PublicID,
  1327. SystemID: DOMString): TDOMDocumentType;
  1328. begin
  1329. // DONE: Implemented
  1330. Result := TDOMDocumentType.Create(nil);
  1331. Result.FName := QualifiedName;
  1332. // cannot have PublicID without SystemID
  1333. if SystemID <> '' then
  1334. begin
  1335. Result.FPublicID := PublicID;
  1336. Result.FSystemID := SystemID;
  1337. end;
  1338. end;
  1339. function TDOMImplementation.CreateDocument(const NamespaceURI,
  1340. QualifiedName: DOMString; doctype: TDOMDocumentType): TDOMDocument;
  1341. var
  1342. Root: TDOMNode;
  1343. begin
  1344. // TODO: This method is not usable yet due to CreateElementNS...
  1345. Result := TDOMDocument.Create;
  1346. Result.FImplementation := Self;
  1347. if Assigned(doctype) then
  1348. begin
  1349. if Assigned(doctype.OwnerDocument) then
  1350. raise EDOMWrongDocument.Create('DOMImplementation.CreateDocument');
  1351. Doctype.FOwnerDocument := Result;
  1352. Result.AppendChild(doctype);
  1353. end;
  1354. Root := Result.CreateElementNS(NamespaceURI, QualifiedName);
  1355. Result.AppendChild(Root);
  1356. end;
  1357. // -------------------------------------------------------
  1358. // Document
  1359. // -------------------------------------------------------
  1360. constructor TDOMDocument.Create;
  1361. begin
  1362. inherited Create(nil);
  1363. // TODO: DOM lvl 2 states that Document should be unowned. Any dependencies?
  1364. FOwnerDocument := Self;
  1365. end;
  1366. function TDOMDocument.GetNodeType: Integer;
  1367. begin
  1368. Result := DOCUMENT_NODE;
  1369. end;
  1370. function TDOMDocument.GetNodeName: DOMString;
  1371. begin
  1372. Result := '#document';
  1373. end;
  1374. function TDOMDocument.GetDocumentElement: TDOMElement;
  1375. var
  1376. node: TDOMNode;
  1377. begin
  1378. node := FFirstChild;
  1379. while Assigned(node) and (node.NodeType <> ELEMENT_NODE) do
  1380. node := node.NextSibling;
  1381. Result := TDOMElement(node);
  1382. end;
  1383. function TDOMDocument.GetDocType: TDOMDocumentType;
  1384. var
  1385. node: TDOMNode;
  1386. begin
  1387. node := FFirstChild;
  1388. while Assigned(node) and (node.NodeType <> DOCUMENT_TYPE_NODE) do
  1389. node := node.NextSibling;
  1390. Result := TDOMDocumentType(node);
  1391. end;
  1392. function TDOMDocument.CreateElement(const tagName: DOMString): TDOMElement;
  1393. begin
  1394. Result := TDOMElement.Create(Self);
  1395. Result.FNodeName := tagName;
  1396. // TODO: attach default attributes
  1397. end;
  1398. function TDOMDocument.CreateElementBuf(Buf: DOMPChar; Length: Integer): TDOMElement;
  1399. begin
  1400. Result := TDOMElement.Create(Self);
  1401. SetString(Result.FNodeName, Buf, Length);
  1402. // TODO: attach default attributes
  1403. end;
  1404. function TDOMDocument.CreateDocumentFragment: TDOMDocumentFragment;
  1405. begin
  1406. Result := TDOMDocumentFragment.Create(Self);
  1407. end;
  1408. function TDOMDocument.CreateTextNode(const data: DOMString): TDOMText;
  1409. begin
  1410. Result := TDOMText.Create(Self);
  1411. Result.FNodeValue := data;
  1412. end;
  1413. function TDOMDocument.CreateTextNodeBuf(Buf: DOMPChar; Length: Integer): TDOMText;
  1414. begin
  1415. Result := TDOMText.Create(Self);
  1416. SetString(Result.FNodeValue, Buf, Length);
  1417. end;
  1418. function TDOMDocument.CreateComment(const data: DOMString): TDOMComment;
  1419. begin
  1420. Result := TDOMComment.Create(Self);
  1421. Result.FNodeValue := data;
  1422. end;
  1423. function TDOMDocument.CreateCommentBuf(Buf: DOMPChar; Length: Integer): TDOMComment;
  1424. begin
  1425. Result := TDOMComment.Create(Self);
  1426. SetString(Result.FNodeValue, Buf, Length);
  1427. end;
  1428. function TDOMDocument.CreateCDATASection(const data: DOMString):
  1429. TDOMCDATASection;
  1430. begin
  1431. raise EDOMNotSupported.Create('DOMDocument.CreateCDATASection');
  1432. Result:=nil;
  1433. end;
  1434. function TDOMDocument.CreateProcessingInstruction(const target,
  1435. data: DOMString): TDOMProcessingInstruction;
  1436. begin
  1437. raise EDOMNotSupported.Create('DOMDocument.CreateProcessingInstruction');
  1438. Result:=nil;
  1439. end;
  1440. function TDOMDocument.CreateAttribute(const name: DOMString): TDOMAttr;
  1441. begin
  1442. Result := TDOMAttr.Create(Self);
  1443. Result.FName := name;
  1444. end;
  1445. function TDOMDocument.CreateAttributeBuf(Buf: DOMPChar; Length: Integer): TDOMAttr;
  1446. begin
  1447. Result := TDOMAttr.Create(Self);
  1448. SetString(Result.FName, Buf, Length);
  1449. end;
  1450. function TDOMDocument.CreateEntityReference(const name: DOMString):
  1451. TDOMEntityReference;
  1452. begin
  1453. raise EDOMNotSupported.Create('DOMDocument.CreateEntityReference');
  1454. Result:=nil;
  1455. end;
  1456. function TDOMDocument.GetElementsByTagName(const tagname: DOMString): TDOMNodeList;
  1457. begin
  1458. Result := TDOMElementList.Create(Self, tagname);
  1459. end;
  1460. function TDOMDocument.GetElementsByTagNameNS(const namespaceURI, localName: DOMString): TDOMNodeList;
  1461. begin
  1462. Result := TDOMElementList.Create(Self, namespaceURI, localName);
  1463. end;
  1464. function TDOMDocument.CreateAttributeNS(const NamespaceURI,
  1465. QualifiedName: DOMString): TDOMAttr;
  1466. begin
  1467. // TODO: Implement TDOMDocument.CreateAttributeNS
  1468. raise EDOMNotSupported.Create('TDOMDocument.CreateAttributeNS');
  1469. Result := nil;
  1470. end;
  1471. function TDOMDocument.CreateElementNS(const NamespaceURI,
  1472. QualifiedName: DOMString): TDOMElement;
  1473. begin
  1474. // TODO: Implement TDOMDocument.CreateElementNS
  1475. raise EDOMNotSupported.Create('TDOMDocument.CreateElementNS');
  1476. Result := nil;
  1477. end;
  1478. function TDOMDocument.GetElementById(
  1479. const ElementID: DOMString): TDOMElement;
  1480. begin
  1481. // TODO: Implement TDOMDocument.GetElementById
  1482. // "Implementations that do not know whether attributes are
  1483. // of type ID or not are expected to return null"
  1484. Result := nil;
  1485. end;
  1486. function TDOMDocument.ImportNode(ImportedNode: TDOMNode;
  1487. Deep: Boolean): TDOMNode;
  1488. begin
  1489. // TODO: Implement TDOMDocument.ImportNode
  1490. raise EDOMNotSupported.Create('TDOMDocument.ImportNode');
  1491. Result := nil;
  1492. end;
  1493. function TXMLDocument.CreateCDATASection(const data: DOMString):
  1494. TDOMCDATASection;
  1495. begin
  1496. Result := TDOMCDATASection.Create(Self);
  1497. Result.FNodeValue := data;
  1498. end;
  1499. function TXMLDocument.CreateProcessingInstruction(const target,
  1500. data: DOMString): TDOMProcessingInstruction;
  1501. begin
  1502. Result := TDOMProcessingInstruction.Create(Self);
  1503. Result.FTarget := target;
  1504. Result.FNodeValue := data;
  1505. end;
  1506. function TXMLDocument.CreateEntityReference(const name: DOMString):
  1507. TDOMEntityReference;
  1508. begin
  1509. Result := TDOMEntityReference.Create(Self);
  1510. Result.FName := name;
  1511. end;
  1512. // -------------------------------------------------------
  1513. // Attr
  1514. // -------------------------------------------------------
  1515. function TDOMAttr.GetNodeType: Integer;
  1516. begin
  1517. Result := ATTRIBUTE_NODE;
  1518. end;
  1519. function TDOMAttr.GetNodeName: DOMString;
  1520. begin
  1521. Result := FName;
  1522. end;
  1523. function TDOMAttr.CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode;
  1524. begin
  1525. // Cloned attribute is always specified and carries its children
  1526. Result := ACloneOwner.CreateAttribute(FName);
  1527. TDOMAttr(Result).FSpecified := True;
  1528. TDOMAttr(Result).FNormalize := FNormalize;
  1529. CloneChildren(Result, ACloneOwner);
  1530. end;
  1531. function TDOMAttr.GetNodeValue: DOMString;
  1532. var
  1533. I,J: Integer;
  1534. begin
  1535. Result := GetTextContent;
  1536. // TODO: probably must be speed optimized
  1537. if FNormalize then
  1538. begin
  1539. Result := Trim(Result);
  1540. I := 1;
  1541. while I < Length(Result) do
  1542. begin
  1543. if Result[I] = #32 then
  1544. begin
  1545. J := I+1;
  1546. while (J <= Length(Result)) and (Result[J] = #32) do Inc(J);
  1547. if J-I > 1 then Delete(Result, I+1, J-I-1);
  1548. end;
  1549. Inc(I);
  1550. end;
  1551. end;
  1552. end;
  1553. procedure TDOMAttr.SetNodeValue(const AValue: DOMString);
  1554. begin
  1555. FSpecified := True;
  1556. SetTextContent(AValue);
  1557. end;
  1558. function TDOMAttr.CompareName(const AName: DOMString): Integer;
  1559. begin
  1560. Result := CompareDOMStrings(DOMPChar(AName), DOMPChar(FName), Length(AName), Length(FName));
  1561. end;
  1562. // -------------------------------------------------------
  1563. // Element
  1564. // -------------------------------------------------------
  1565. function TDOMElement.GetNodeType: Integer;
  1566. begin
  1567. Result := ELEMENT_NODE;
  1568. end;
  1569. function TDOMElement.GetNodeName: DOMString;
  1570. begin
  1571. Result := FNodeName;
  1572. end;
  1573. destructor TDOMElement.Destroy;
  1574. begin
  1575. // FIX: Attribute nodes are now freed by TDOMNamedNodeMap.Destroy
  1576. FreeAndNil(FAttributes);
  1577. inherited Destroy;
  1578. end;
  1579. function TDOMElement.CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode;
  1580. var
  1581. i: Integer;
  1582. begin
  1583. Result := ACloneOwner.CreateElement(FNodeName);
  1584. if Assigned(FAttributes) then
  1585. begin
  1586. for i := 0 to FAttributes.Length - 1 do
  1587. TDOMElement(Result).SetAttributeNode(TDOMAttr(FAttributes[i].CloneNode(True, ACloneOwner)));
  1588. end;
  1589. if deep then
  1590. CloneChildren(Result, ACloneOwner);
  1591. end;
  1592. function TDOMElement.GetAttributes: TDOMNamedNodeMap;
  1593. begin
  1594. if FAttributes=nil then
  1595. FAttributes := TDOMNamedNodeMap.Create(Self, ATTRIBUTE_NODE);
  1596. Result := FAttributes;
  1597. end;
  1598. function TDOMElement.GetAttribute(const name: DOMString): DOMString;
  1599. var
  1600. Attr: TDOMNode;
  1601. begin
  1602. SetLength(Result, 0);
  1603. if Assigned(FAttributes) then
  1604. begin
  1605. Attr := FAttributes.GetNamedItem(name);
  1606. if Assigned(Attr) then
  1607. Result := Attr.NodeValue;
  1608. end;
  1609. end;
  1610. function TDOMElement.GetAttributeNS(const namespaceURI, localName: DOMString): DOMString;
  1611. var
  1612. Attr: TDOMNode;
  1613. begin
  1614. SetLength(Result, 0);
  1615. if Assigned(FAttributes) then
  1616. begin
  1617. Attr := FAttributes.GetNamedItemNS(namespaceURI, localName);
  1618. if Assigned(Attr) then
  1619. Result := Attr.NodeValue;
  1620. end;
  1621. end;
  1622. procedure TDOMElement.SetAttribute(const name, value: DOMString);
  1623. var
  1624. I: Cardinal;
  1625. attr: TDOMAttr;
  1626. begin
  1627. if Attributes.Find(name, I) then
  1628. Attr := FAttributes[I] as TDOMAttr
  1629. else
  1630. begin
  1631. Attr := FOwnerDocument.CreateAttribute(name);
  1632. FAttributes.FList.Insert(I, Attr);
  1633. end;
  1634. attr.NodeValue := value;
  1635. end;
  1636. procedure TDOMElement.RemoveAttribute(const name: DOMString);
  1637. begin
  1638. // (note) NamedNodeMap.RemoveNamedItem can raise NOT_FOUND_ERR and we should not.
  1639. if Assigned(FAttributes) then
  1640. FAttributes.InternalRemove(name).Free;
  1641. end;
  1642. procedure TDOMElement.RemoveAttributeNS(const namespaceURI,
  1643. localName: DOMString);
  1644. begin
  1645. // TODO: Implement TDOMElement.RemoveAttributeNS
  1646. raise EDOMNotSupported.Create('TDOMElement.RemoveAttributeNS');
  1647. end;
  1648. procedure TDOMElement.SetAttributeNS(const namespaceURI, qualifiedName,
  1649. value: DOMString);
  1650. var
  1651. Attr: TDOMAttr;
  1652. begin
  1653. Attr := Attributes.GetNamedItemNS(namespaceURI, qualifiedName) as TDOMAttr;
  1654. if attr = nil then
  1655. begin
  1656. attr := FOwnerDocument.CreateAttributeNS(namespaceURI, qualifiedName);
  1657. // TODO 5: keep sorted!
  1658. FAttributes.FList.Add(attr);
  1659. end;
  1660. attr.NodeValue := value;
  1661. end;
  1662. function TDOMElement.GetAttributeNode(const name: DOMString): TDOMAttr;
  1663. begin
  1664. // DONE: delegated to TNamedNodeMap.GetNamedItem
  1665. if Assigned(FAttributes) then
  1666. Result := FAttributes.GetNamedItem(name) as TDOMAttr
  1667. else
  1668. Result := nil;
  1669. end;
  1670. function TDOMElement.GetAttributeNodeNS(const namespaceURI, localName: DOMString): TDOMAttr;
  1671. begin
  1672. if Assigned(FAttributes) then
  1673. Result := FAttributes.GetNamedItemNS(namespaceURI, localName) as TDOMAttr
  1674. else
  1675. Result := nil;
  1676. end;
  1677. function TDOMElement.SetAttributeNode(NewAttr: TDOMAttr): TDOMAttr;
  1678. begin
  1679. Result := Attributes.SetNamedItem(NewAttr) as TDOMAttr;
  1680. // TODO -cConformance: here goes inconsistency with DOM 2 - same as in TDOMNode.RemoveChild
  1681. Result.Free;
  1682. Result := nil;
  1683. end;
  1684. function TDOMElement.SetAttributeNodeNS(NewAttr: TDOMAttr): TDOMAttr;
  1685. begin
  1686. Result := Attributes.SetNamedItemNS(NewAttr) as TDOMAttr;
  1687. // TODO -cConformance: here goes inconsistency with DOM 2 - same as in TDOMNode.RemoveChild
  1688. Result.Free;
  1689. Result := nil;
  1690. end;
  1691. function TDOMElement.RemoveAttributeNode(OldAttr: TDOMAttr): TDOMAttr;
  1692. begin
  1693. Result:=nil;
  1694. if FAttributes=nil then exit;
  1695. // TODO: DOM 2: must raise NOT_FOUND_ERR if OldAttr is not ours.
  1696. // -- but what is the purpose of return value then?
  1697. // TODO: delegate to TNamedNodeMap? Nope, it does not have such method
  1698. // (note) one way around is to remove by name
  1699. if FAttributes.FList.Remove(OldAttr) > -1 then
  1700. Result := OldAttr;
  1701. end;
  1702. function TDOMElement.GetElementsByTagName(const name: DOMString): TDOMNodeList;
  1703. begin
  1704. Result := TDOMElementList.Create(Self, name);
  1705. end;
  1706. function TDOMElement.GetElementsByTagNameNS(const namespaceURI, localName: DOMString): TDOMNodeList;
  1707. begin
  1708. Result := TDOMElementList.Create(Self, namespaceURI, localName);
  1709. end;
  1710. function TDOMElement.hasAttribute(const name: DOMString): Boolean;
  1711. begin
  1712. Result := Assigned(FAttributes) and
  1713. Assigned(FAttributes.GetNamedItem(name));
  1714. end;
  1715. function TDOMElement.hasAttributeNS(const namespaceURI, localName: DOMString): Boolean;
  1716. begin
  1717. Result := Assigned(FAttributes) and
  1718. Assigned(FAttributes.getNamedItemNS(namespaceURI, localName));
  1719. end;
  1720. function TDOMElement.HasAttributes: Boolean;
  1721. begin
  1722. Result := Assigned(FAttributes) and (FAttributes.Length > 0);
  1723. end;
  1724. function TDOMElement.CompareName(const Name: DOMString): Integer;
  1725. begin
  1726. Result := CompareDOMStrings(DOMPChar(name), DOMPChar(FNodeName), Length(name), Length(FNodeName));
  1727. end;
  1728. // -------------------------------------------------------
  1729. // Text
  1730. // -------------------------------------------------------
  1731. function TDOMText.GetNodeType: Integer;
  1732. begin
  1733. Result := TEXT_NODE;
  1734. end;
  1735. function TDOMText.GetNodeName: DOMString;
  1736. begin
  1737. Result := '#text';
  1738. end;
  1739. function TDOMText.CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode;
  1740. begin
  1741. Result := ACloneOwner.CreateTextNode(FNodeValue);
  1742. end;
  1743. function TDOMText.SplitText(offset: LongWord): TDOMText;
  1744. begin
  1745. if offset > Length then
  1746. raise EDOMIndexSize.Create('Text.SplitText');
  1747. Result := TDOMText.Create(FOwnerDocument);
  1748. Result.FNodeValue := Copy(FNodeValue, offset + 1, Length);
  1749. FNodeValue := Copy(FNodeValue, 1, offset);
  1750. FParentNode.InsertBefore(Result, FNextSibling);
  1751. end;
  1752. // -------------------------------------------------------
  1753. // Comment
  1754. // -------------------------------------------------------
  1755. function TDOMComment.GetNodeType: Integer;
  1756. begin
  1757. Result := COMMENT_NODE;
  1758. end;
  1759. function TDOMComment.GetNodeName: DOMString;
  1760. begin
  1761. Result := '#comment';
  1762. end;
  1763. function TDOMComment.CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode;
  1764. begin
  1765. Result := ACloneOwner.CreateComment(FNodeValue);
  1766. end;
  1767. // -------------------------------------------------------
  1768. // CDATASection
  1769. // -------------------------------------------------------
  1770. function TDOMCDATASection.GetNodeType: Integer;
  1771. begin
  1772. Result := CDATA_SECTION_NODE;
  1773. end;
  1774. function TDOMCDATASection.GetNodeName: DOMString;
  1775. begin
  1776. Result := '#cdata-section';
  1777. end;
  1778. function TDOMCDATASection.CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode;
  1779. begin
  1780. Result := ACloneOwner.CreateCDATASection(FNodeValue);
  1781. end;
  1782. // -------------------------------------------------------
  1783. // DocumentType
  1784. // -------------------------------------------------------
  1785. function TDOMDocumentType.GetNodeType: Integer;
  1786. begin
  1787. Result := DOCUMENT_TYPE_NODE;
  1788. end;
  1789. function TDOMDocumentType.GetNodeName: DOMString;
  1790. begin
  1791. Result := FName;
  1792. end;
  1793. destructor TDOMDocumentType.Destroy;
  1794. begin
  1795. FEntities.Free;
  1796. FNotations.Free;
  1797. inherited Destroy;
  1798. end;
  1799. function TDOMDocumentType.CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode;
  1800. begin
  1801. Result := TDOMDocumentType.Create(ACloneOwner);
  1802. TDOMDocumentType(Result).FName := FName;
  1803. TDOMDocumentType(Result).FSystemID := FSystemID;
  1804. TDOMDocumentType(Result).FPublicID := FPublicID;
  1805. // ignore deep - DocumentType cannot have children
  1806. // TODO: Clone Entities and Notations
  1807. end;
  1808. function TDOMDocumentType.GetEntities: TDOMNamedNodeMap;
  1809. begin
  1810. if FEntities = nil then
  1811. FEntities := TDOMNamedNodeMap.Create(Self, ENTITY_NODE);
  1812. Result := FEntities;
  1813. end;
  1814. function TDOMDocumentType.GetNotations: TDOMNamedNodeMap;
  1815. begin
  1816. if FNotations = nil then
  1817. FNotations := TDOMNamedNodeMap.Create(Self, NOTATION_NODE);
  1818. Result := FNotations;
  1819. end;
  1820. // -------------------------------------------------------
  1821. // Notation
  1822. // -------------------------------------------------------
  1823. function TDOMNotation.GetNodeType: Integer;
  1824. begin
  1825. Result := NOTATION_NODE;
  1826. end;
  1827. function TDOMNotation.GetNodeName: DOMString;
  1828. begin
  1829. Result := FName;
  1830. end;
  1831. function TDOMNotation.CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode;
  1832. begin
  1833. Result := TDOMNotation.Create(ACloneOwner);
  1834. TDOMNotation(Result).FName := FName;
  1835. TDOMNotation(Result).FPublicID := PublicID;
  1836. TDOMNotation(Result).FSystemID := SystemID;
  1837. // notation cannot have children, ignore Deep
  1838. end;
  1839. // -------------------------------------------------------
  1840. // Entity
  1841. // -------------------------------------------------------
  1842. function TDOMEntity.GetNodeType: Integer;
  1843. begin
  1844. Result := ENTITY_NODE;
  1845. end;
  1846. function TDOMEntity.GetNodeName: DOMString;
  1847. begin
  1848. Result := FName;
  1849. end;
  1850. // -------------------------------------------------------
  1851. // EntityReference
  1852. // -------------------------------------------------------
  1853. function TDOMEntityReference.GetNodeType: Integer;
  1854. begin
  1855. Result := ENTITY_REFERENCE_NODE;
  1856. end;
  1857. function TDOMEntityReference.GetNodeName: DOMString;
  1858. begin
  1859. Result := FName;
  1860. end;
  1861. function TDOMEntityReference.CloneNode(deep: Boolean; ACloneOwner: TDOMDocument): TDOMNode;
  1862. begin
  1863. Result := ACloneOwner.CreateEntityReference(FName);
  1864. CloneChildren(Result, ACloneOwner);
  1865. end;
  1866. // -------------------------------------------------------
  1867. // ProcessingInstruction
  1868. // -------------------------------------------------------
  1869. function TDOMProcessingInstruction.CloneNode(deep: Boolean;
  1870. ACloneOwner: TDOMDocument): TDOMNode;
  1871. begin
  1872. Result := ACloneOwner.CreateProcessingInstruction(Target, Data);
  1873. end;
  1874. function TDOMProcessingInstruction.GetNodeType: Integer;
  1875. begin
  1876. Result := PROCESSING_INSTRUCTION_NODE;
  1877. end;
  1878. function TDOMProcessingInstruction.GetNodeName: DOMString;
  1879. begin
  1880. Result := FTarget;
  1881. end;
  1882. function TDOMProcessingInstruction.GetNodeValue: DOMString;
  1883. begin
  1884. Result := FNodeValue;
  1885. end;
  1886. procedure TDOMProcessingInstruction.SetNodeValue(const AValue: DOMString);
  1887. begin
  1888. FNodeValue := AValue;
  1889. end;
  1890. end.