XmlNode.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  1. // -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
  2. //
  3. // System.Xml.XmlNode
  4. //
  5. // Author:
  6. // Daniel Weber ([email protected])
  7. //
  8. // (C) 2001 Daniel Weber
  9. using System;
  10. using System.Collections;
  11. using System.Xml.XPath;
  12. namespace System.Xml
  13. {
  14. public abstract class XmlNode : ICloneable, IEnumerable, IXPathNavigable
  15. {
  16. //======= Private data members ==============================================
  17. private XmlNodeListAsArrayList _childNodes;
  18. protected XmlDocument FOwnerDocument;
  19. protected XmlNode _parent;
  20. // Names of node
  21. // for <foo:bar xmlns:foo="http://www.foobar.com/schema/foobar">... </foo:bar>
  22. // qualified name: foo:bar
  23. // namespaceURI = "http://www.foobar.com/schema/foobar"
  24. // localName = bar
  25. // prefix = foo
  26. // Note that namespaces can be nested (child namespace != parent namespace)
  27. // namespaces are optional
  28. protected string Fname;
  29. protected string FnamespaceURI;
  30. protected string Fprefix;
  31. protected string FlocalName;
  32. // baseURI holds the location from which the document was loaded
  33. // If the node was created from a document at c:\tmp.xml, then that's what will be here
  34. protected string FbaseURI;
  35. // value of the node (overriden in classes that do something different)
  36. // default behavior is just to store it
  37. protected string Fvalue;
  38. //=====================================================================
  39. // ============ Properties ============================================
  40. //=====================================================================
  41. /// <summary>
  42. /// Get the XmlAttributeCollection representing the attributes
  43. /// on the node type. Returns null if the node type is not XmlElement.
  44. /// </summary>
  45. public virtual XmlAttributeCollection Attributes
  46. {
  47. get
  48. {
  49. return null;
  50. }
  51. }
  52. /// <summary>
  53. /// Return the base Uniform Resource Indicator (URI) used to resolve
  54. /// this node, or String.Empty.
  55. /// </summary>
  56. public virtual string BaseURI
  57. {
  58. get
  59. {
  60. return FbaseURI;
  61. }
  62. }
  63. /// <summary>
  64. /// Return all child nodes of this node. If there are no children,
  65. /// return an empty XmlNodeList;
  66. /// </summary>
  67. public virtual XmlNodeList ChildNodes
  68. {
  69. get
  70. {
  71. if (_childNodes == null)
  72. _childNodes = new XmlNodeListAsArrayList();
  73. return _childNodes as XmlNodeList;
  74. }
  75. }
  76. /// <summary>
  77. /// Return first child node as XmlNode or null
  78. /// if the node has no children
  79. /// </summary>
  80. public virtual XmlNode FirstChild
  81. {
  82. get
  83. {
  84. if (ChildNodes.Count == 0)
  85. return null;
  86. else
  87. return ChildNodes[0];
  88. }
  89. }
  90. /// <summary>
  91. /// Return true if the node has children
  92. /// </summary>
  93. public virtual bool HasChildNodes
  94. {
  95. get
  96. {
  97. if (ChildNodes.Count == 0)
  98. return true;
  99. else
  100. return false;
  101. }
  102. }
  103. /// <summary>
  104. /// Get or Set the concatenated values of node and children
  105. /// </summary>
  106. public virtual string InnerText
  107. {
  108. get
  109. {
  110. // TODO - implement set InnerText()
  111. throw new NotImplementedException();
  112. }
  113. set
  114. {
  115. // TODO - implement set InnerText()
  116. throw new NotImplementedException();
  117. }
  118. }
  119. /// <summary>
  120. /// Get/Set the XML representing just the child nodes of this node
  121. /// </summary>
  122. public virtual string InnerXml
  123. {
  124. get
  125. {
  126. // TODO - implement set InnerXml()
  127. throw new NotImplementedException();
  128. }
  129. set
  130. {
  131. // TODO - implement set InnerXml()
  132. throw new NotImplementedException();
  133. }
  134. }
  135. /// <summary>
  136. /// Property Get - true if node is read-only
  137. /// </summary>
  138. public virtual bool IsReadOnly
  139. {
  140. get
  141. {
  142. return OwnerDocument.IsReadOnly;
  143. }
  144. }
  145. /// <summary>
  146. /// Return the child element named [string]. Returns XmlElement
  147. /// Indexer for XmlNode class.
  148. /// </summary>
  149. [System.Runtime.CompilerServices.IndexerNameAttribute("Item")]
  150. public virtual XmlElement this [String index]
  151. {
  152. get
  153. {
  154. // TODO - implement XmlNode.Item(string)
  155. throw new NotImplementedException();
  156. }
  157. }
  158. /// <summary>
  159. /// Get the last child node, or null if there are no nodes
  160. /// </summary>
  161. public virtual XmlNode LastChild
  162. {
  163. get
  164. {
  165. if (_childNodes.Count == 0)
  166. return null;
  167. else
  168. return _childNodes.Item(_childNodes.Count - 1);
  169. }
  170. }
  171. /// <summary>
  172. /// Returns the local name of the node with qualifiers removed
  173. /// LocalName of ns:elementName = "elementName"
  174. /// </summary>
  175. public abstract string LocalName {get;}
  176. /// <summary>
  177. /// Get the qualified node name
  178. /// derived classes must implement as behavior varies
  179. /// by tag type.
  180. /// </summary>
  181. public abstract string Name { get; }
  182. /// <summary>
  183. /// Get the namespace URI or String.Empty if none
  184. /// </summary>
  185. public virtual string NamespaceURI
  186. {
  187. get
  188. {
  189. // TODO - implement Namespace URI, or determine abstractness
  190. throw new NotImplementedException("XmlNode.NamespaceURI not implemented");
  191. }
  192. }
  193. /// <summary>
  194. /// Get the node immediatelly following this node, or null
  195. /// </summary>
  196. public virtual XmlNode NextSibling
  197. {
  198. get
  199. {
  200. if (_parent != null)
  201. {
  202. XmlNodeListAsArrayList children = _parent.ChildNodes as XmlNodeListAsArrayList;
  203. int ourIndex = children.data.IndexOf(this);
  204. return children[ourIndex + 1];
  205. }
  206. else
  207. return null;
  208. }
  209. }
  210. public virtual XmlNodeType NodeType
  211. {
  212. get
  213. {
  214. return XmlNodeType.None;
  215. }
  216. }
  217. /// <summary>
  218. /// Return the string representing this node and all it's children
  219. /// </summary>
  220. public virtual string OuterXml
  221. {
  222. get
  223. {
  224. // TODO - implement OuterXml {get;}
  225. throw new NotImplementedException();
  226. }
  227. }
  228. /// <summary>
  229. /// Return owning document.
  230. /// If this nodeType is a document, return null
  231. /// </summary>
  232. public virtual XmlDocument OwnerDocument
  233. {
  234. get
  235. {
  236. return FOwnerDocument;
  237. }
  238. }
  239. /// <summary>
  240. /// Returns the parent node, or null
  241. /// Return value depends on superclass node type
  242. /// </summary>
  243. public virtual XmlNode ParentNode
  244. {
  245. get
  246. {
  247. return _parent;
  248. }
  249. }
  250. /// <summary>
  251. /// set/get the namespace prefix for this node, or
  252. /// string.empty if it does not exist
  253. /// </summary>
  254. public virtual string Prefix
  255. {
  256. get
  257. {
  258. return Fprefix;
  259. }
  260. set
  261. {
  262. // TODO - validation on XmlNode.Prefix {set;}? (no)
  263. Fprefix = value;
  264. }
  265. }
  266. /// <summary>
  267. /// The preceding XmlNode or null
  268. /// </summary>
  269. public virtual XmlNode PreviousSibling {
  270. get
  271. {
  272. if (_parent != null)
  273. {
  274. XmlNodeListAsArrayList children = _parent.ChildNodes as XmlNodeListAsArrayList;
  275. int ourIndex = children.data.IndexOf(this);
  276. return children[ourIndex - 1];
  277. }
  278. else
  279. return null;
  280. }
  281. }
  282. /// <summary>
  283. /// Get/Set the value for this node
  284. /// </summary>
  285. public virtual string Value
  286. {
  287. get
  288. {
  289. return Fvalue;
  290. }
  291. set
  292. {
  293. Fvalue = value;
  294. }
  295. }
  296. //=====================================================================
  297. //======= Methods =====================================================
  298. //=====================================================================
  299. /// <summary>
  300. /// Appends the specified node to the end of the child node list
  301. /// </summary>
  302. /// <param name="newChild"></param>
  303. /// <returns></returns>
  304. public virtual XmlNode AppendChild (XmlNode newChild)
  305. {
  306. return InsertBefore(newChild, null);
  307. }
  308. /// <summary>
  309. /// Return a clone of this node
  310. /// </summary>
  311. /// <returns></returns>
  312. public virtual object Clone()
  313. {
  314. // TODO - implement XmlNode.Clone() as object
  315. throw new NotImplementedException("object XmlNode.Clone() not implmented");
  316. }
  317. /// <summary>
  318. /// Return a clone of the node
  319. /// </summary>
  320. /// <param name="deep">Make copy of all children</param>
  321. /// <returns>Cloned node</returns>
  322. public abstract XmlNode CloneNode( bool deep);
  323. /// <summary>
  324. /// Return an XPathNavigator for navigating this node
  325. /// </summary>
  326. /// <returns></returns>
  327. public System.Xml.XPath.XPathNavigator CreateNavigator()
  328. {
  329. // TODO - implement CreateNavigator()
  330. throw new NotImplementedException();
  331. }
  332. /// <summary>
  333. /// Provide support for "for each"
  334. /// </summary>
  335. /// <returns></returns>
  336. public IEnumerator GetEnumerator()
  337. {
  338. return _childNodes.data.GetEnumerator();
  339. }
  340. /// <summary>
  341. /// Look up the closest namespace for this node that is in scope for the given prefix
  342. /// </summary>
  343. /// <param name="prefix"></param>
  344. /// <returns>Namespace URI</returns>
  345. public virtual string GetNamespaceOfPrefix(string prefix)
  346. {
  347. // TODO - implement GetNamespaceOfPrefix()
  348. throw new NotImplementedException();
  349. }
  350. /// <summary>
  351. /// Get the closest xmlns declaration for the given namespace URI that is in scope.
  352. /// Returns the prefix defined in that declaration.
  353. /// </summary>
  354. /// <param name="namespaceURI"></param>
  355. /// <returns></returns>
  356. public virtual string GetPrefixOfNamespace(string namespaceURI)
  357. {
  358. // TODO - implement GetPrefixOfNamespace
  359. throw new NotImplementedException();
  360. }
  361. /// <summary>
  362. /// Insert newChild directly after the reference node.
  363. /// If refChild is null, newChild is inserted at the beginning of childnodes.
  364. /// If newChild is a document fragment, all nodes are inserted after refChild.
  365. /// If newChild is already in the tree, it is first removed.
  366. /// </summary>
  367. /// <exception cref="ArgumentException">NewChild was created from differant document.
  368. /// RefChild not a child of this node or null.
  369. /// Node is read-only</exception>
  370. /// <exception cref="InvalidOperationException">Node is of type that does not have children
  371. /// Node to insert is an ancestor of this node.</exception>
  372. /// <param name="newChild">Child node to insert.</param>
  373. /// <param name="refChild">Reference node to insert after</param>
  374. /// <returns>Removed node, or null if no node removed.</returns>
  375. public virtual XmlNode InsertAfter(XmlNode newChild, XmlNode refChild)
  376. {
  377. // Checks parent not ancestor, arguments valid, etc. Throws exception on error
  378. InsertionCheck(newChild, refChild);
  379. // Scan the node list, looking for refChild and seeing if newChild is in the list
  380. // Note that if refNode is null (prepend), we don't want to do the .Equals(null)
  381. XmlNode retval = null;
  382. int refNodeIndex = -1;
  383. for (int i = 0; i < _childNodes.Count; i++)
  384. {
  385. XmlNode e = _childNodes.data[i] as XmlNode;
  386. if (e.Equals(newChild))
  387. {
  388. retval = e;
  389. FOwnerDocument.onNodeRemoving(newChild, newChild.ParentNode);
  390. _childNodes.data.RemoveAt(i);
  391. newChild.setParent(null);
  392. FOwnerDocument.onNodeRemoved(newChild, null);
  393. break;
  394. }
  395. if ( (refChild != null ) & ( e.Equals(refChild) ) )
  396. {
  397. refNodeIndex = i;
  398. if (retval != null)
  399. break;
  400. }
  401. }
  402. if ( ( refNodeIndex == -1 ) & (refChild != null) )
  403. throw new ArgumentException("Reference node not found (and not null) in call to XmlNode.InsertAfter()");
  404. FOwnerDocument.onNodeInserting(newChild, this);
  405. if (refChild == null)
  406. refNodeIndex = 0;
  407. else
  408. refNodeIndex++; // insert after reference...
  409. if (newChild.NodeType == XmlNodeType.DocumentFragment)
  410. {
  411. // Insert all children, starting from refNodeIndex (0,1,2...n)
  412. for (int i = 0; i < newChild.ChildNodes.Count; i++)
  413. {
  414. XmlNode e = newChild.ChildNodes[i] as XmlNode;
  415. FOwnerDocument.onNodeInserting(e, this);
  416. _childNodes.data.Insert(refNodeIndex, newChild.ChildNodes[i]);
  417. e.setParent(this);
  418. FOwnerDocument.onNodeInserted(newChild, this);
  419. refNodeIndex ++;
  420. }
  421. }
  422. else
  423. {
  424. FOwnerDocument.onNodeInserting(newChild, this);
  425. _childNodes.data.Insert(refNodeIndex, newChild);
  426. newChild.setParent(this);
  427. FOwnerDocument.onNodeInserted(newChild, this);
  428. }
  429. return retval;
  430. }
  431. /// <summary>
  432. /// Insert newChild directly before the reference node.
  433. /// If refChild is null, newChild is inserted at the end of childnodes.
  434. /// If newChild is a document fragment, all nodes are inserted before refChild.
  435. /// If newChild is already in the tree, it is first removed.
  436. /// </summary>
  437. /// <exception cref="ArgumentException">NewChild was created from different document.
  438. /// RefChild not a child of this node, or is null.
  439. /// Node is read-only</exception>
  440. /// <exception cref="InvalidOperationException">Node is of type that does not have children.
  441. /// Node to insert is an ancestor of this node.</exception>
  442. /// <param name="newChild">Child node to insert.</param>
  443. /// <param name="refChild">Reference node to insert after</param>
  444. /// <returns>Removed node, or null if no node removed.</returns>
  445. public virtual XmlNode InsertBefore(XmlNode newChild, XmlNode refChild)
  446. {
  447. // Checks parent not ancestor, arguments valid, etc. Throws exception on error
  448. InsertionCheck(newChild, refChild);
  449. // Scan the node list, looking for refChild and seeing if newChild is in the list
  450. XmlNode retval = null;
  451. int refNodeIndex = -1;
  452. for (int i = 0; i < _childNodes.Count; i++)
  453. {
  454. XmlNode e = _childNodes.data[i] as XmlNode;
  455. if (e.Equals(newChild))
  456. {
  457. retval = e;
  458. FOwnerDocument.onNodeRemoving(newChild, newChild.ParentNode);
  459. _childNodes.data.RemoveAt(i);
  460. newChild.setParent(null);
  461. FOwnerDocument.onNodeRemoved(newChild, null);
  462. break;
  463. }
  464. if ( (refChild != null ) & ( e.Equals(refChild) ) )
  465. {
  466. refNodeIndex = i;
  467. if (retval != null)
  468. break;
  469. }
  470. }
  471. if ( ( refNodeIndex == -1 ) & (refChild != null) )
  472. throw new ArgumentException("Reference node not found (and not null) in call to XmlNode.InsertAfter()");
  473. if (refChild == null)
  474. refNodeIndex = _childNodes.Count;
  475. if (newChild.NodeType == XmlNodeType.DocumentFragment)
  476. {
  477. // Insert all children, starting from refNodeIndex (0,1,2...n)
  478. for (int i = 0; i < newChild.ChildNodes.Count; i++)
  479. {
  480. XmlNode e = newChild.ChildNodes[i] as XmlNode;
  481. FOwnerDocument.onNodeInserting(e, this);
  482. _childNodes.data.Insert(refNodeIndex, newChild.ChildNodes[i]);
  483. e.setParent(this);
  484. FOwnerDocument.onNodeInserted(newChild, this);
  485. refNodeIndex ++;
  486. }
  487. }
  488. else
  489. {
  490. FOwnerDocument.onNodeInserting(newChild, this);
  491. _childNodes.data.Insert(refNodeIndex, newChild);
  492. newChild.setParent(this);
  493. FOwnerDocument.onNodeInserted(newChild, this);
  494. }
  495. return retval;
  496. }
  497. /// <summary>
  498. /// Put all nodes under this node in "normal" form
  499. /// Whatever that means...
  500. /// </summary>
  501. public virtual void Normalize()
  502. {
  503. // TODO - Implement Normalize()
  504. throw new NotImplementedException();
  505. }
  506. /// <summary>
  507. /// Add the specified child to the beginning of the child node list
  508. /// </summary>
  509. /// <param name="newChild">Node to add</param>
  510. /// <returns>The node added</returns>
  511. public virtual XmlNode PrependChild(XmlNode newChild)
  512. {
  513. return InsertAfter(newChild, null);
  514. }
  515. /// <summary>
  516. /// Remove all children and attributes
  517. /// </summary>
  518. public virtual void RemoveAll()
  519. {
  520. if (_childNodes == null)
  521. return;
  522. else
  523. {
  524. // Remove in order, 0..n
  525. while (_childNodes.Count > 0)
  526. {
  527. XmlNode e = _childNodes[0];
  528. FOwnerDocument.onNodeRemoving(e, this);
  529. e.setParent(null);
  530. _childNodes.data.RemoveAt(0);
  531. FOwnerDocument.onNodeRemoved(e, null);
  532. }
  533. }
  534. }
  535. /// <summary>
  536. /// Remove specified child node
  537. /// </summary>
  538. /// <param name="oldChild"></param>
  539. /// <returns>Removed node</returns>
  540. public virtual XmlNode RemoveChild(XmlNode oldChild)
  541. {
  542. // TODO - implement RemoveChild(oldChild)
  543. throw new NotImplementedException();
  544. }
  545. /// <summary>
  546. /// Select a list of nodes matching the xpath
  547. /// </summary>
  548. /// <param name="xpath"></param>
  549. /// <returns>matching nodes</returns>
  550. public XmlNodeList SelectNodes( string xpath)
  551. {
  552. // TODO - imlement SelectNodes(xpath)
  553. throw new NotImplementedException();
  554. }
  555. /// <summary>
  556. /// Select a list of nodes matching the xpath. Any prefixes are resolved
  557. /// using the passed namespace manager
  558. /// </summary>
  559. /// <param name="xpath"></param>
  560. /// <param name="nsmgr"></param>
  561. /// <returns></returns>
  562. public XmlNodeList SelectNodes(string xpath, XmlNamespaceManager nsmgr)
  563. {
  564. // TODO - implement SelectNodes(xpath, nsmgr)
  565. throw new NotImplementedException();
  566. }
  567. /// <summary>
  568. /// Selects the first node that matches xpath
  569. /// </summary>
  570. /// <param name="?"></param>
  571. /// <returns></returns>
  572. public XmlNode SelectSingleNode(string xpatch)
  573. {
  574. // TODO - implement SelectSingeNode(xpath)
  575. throw new NotImplementedException();
  576. }
  577. /// <summary>
  578. /// Returns the first node that matches xpath
  579. /// Uses the passed namespace manager to resolve namespace URI's
  580. /// </summary>
  581. /// <param name="xpath"></param>
  582. /// <param name="nsmgr"></param>
  583. /// <returns></returns>
  584. public XmlNode SelectSingleNode(string xpath, XmlNamespaceManager nsmgr)
  585. {
  586. // Implement SelectSingleNode(xpath, nsmgr)
  587. throw new NotImplementedException();
  588. }
  589. /// <summary>
  590. /// Tests if the DOM implementation supports the passed feature
  591. /// </summary>
  592. /// <param name="feature"></param>
  593. /// <param name="version"></param>
  594. /// <returns></returns>
  595. public virtual bool Supports(string feature, string version)
  596. {
  597. //TODO - implement Supports(feature, version)
  598. throw new NotImplementedException();
  599. }
  600. /// <summary>
  601. /// Returns a string representation of the current node and it's children
  602. /// </summary>
  603. /// <returns></returns>
  604. public override string ToString()
  605. {
  606. // TODO - implement ToString()
  607. throw new NotImplementedException();
  608. }
  609. /// <summary>
  610. /// Saves all children of the current node to the passed writer
  611. /// </summary>
  612. /// <param name="w"></param>
  613. public abstract void WriteContentTo(XmlWriter w);
  614. /// <summary>
  615. /// Saves the current node to writer w
  616. /// </summary>
  617. /// <param name="w"></param>
  618. public abstract void WriteTo(XmlWriter w);
  619. //======= Internal methods ===============================================
  620. /// <summary>
  621. /// accessor {set;} for parentNode only visible internally.
  622. /// </summary>
  623. /// <param name="newParent">new parent node.</param>
  624. internal void setParent( XmlNode newParent)
  625. {
  626. if (newParent.OwnerDocument.Equals( FOwnerDocument) )
  627. _parent = newParent;
  628. else
  629. throw new ArgumentException("New parent node owner does not match");
  630. }
  631. //======= Protected methods ==============================================
  632. //======= Private Methods ===================================================
  633. /// <summary>
  634. /// Helper function to perform checks required before insrting a node.
  635. /// Throws applicable exceptions on error.
  636. /// </summary>
  637. /// <param name="newChild"></param>
  638. /// <param name="refChild"></param>
  639. private void InsertionCheck( XmlNode newChild, XmlNode refChild)
  640. {
  641. if (newChild == null)
  642. throw new ArgumentNullException("Null newNode passed to InsertAfter()");
  643. if (newChild.Equals(this))
  644. throw new ArgumentException("Cannot insert node onto itself");
  645. if (! FOwnerDocument.Equals( newChild.OwnerDocument) )
  646. throw new ArgumentException("Reference node has different owner document than this node");
  647. if ( FOwnerDocument.IsReadOnly )
  648. throw new ArgumentException("Operation not supported - tree is read-only");
  649. //Check that insert node is not in our path to the root
  650. XmlNode curParent = _parent;
  651. while ( (curParent != null) & (! FOwnerDocument.Equals(curParent) ))
  652. {
  653. if (curParent.Equals(newChild) )
  654. throw new ArgumentException("Cannot insert ancestor a node");
  655. curParent = curParent.ParentNode;
  656. }
  657. }
  658. // Constructors
  659. //===========================================================================
  660. //When we're first created, we won't know parent, etc.
  661. internal XmlNode( XmlDocument aOwnerDoc )
  662. {
  663. // Don't create childnodes object, since not all derived classes have children
  664. FOwnerDocument = aOwnerDoc;
  665. }
  666. } // XmlNode
  667. } // using namespace System.Xml