PageRenderTime 52ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/class/System.XML/System.Xml/XmlNode.cs

https://bitbucket.org/danipen/mono
C# | 907 lines | 704 code | 132 blank | 71 comment | 228 complexity | 0bc62a62b5ef1a9795e73bbf44babbca MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. //
  2. // System.Xml.XmlNode
  3. //
  4. // Author:
  5. // Kral Ferch <kral_ferch@hotmail.com>
  6. // Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
  7. //
  8. // (C) 2002 Kral Ferch
  9. // (C) 2002 Atsushi Enomoto
  10. //
  11. //
  12. // Permission is hereby granted, free of charge, to any person obtaining
  13. // a copy of this software and associated documentation files (the
  14. // "Software"), to deal in the Software without restriction, including
  15. // without limitation the rights to use, copy, modify, merge, publish,
  16. // distribute, sublicense, and/or sell copies of the Software, and to
  17. // permit persons to whom the Software is furnished to do so, subject to
  18. // the following conditions:
  19. //
  20. // The above copyright notice and this permission notice shall be
  21. // included in all copies or substantial portions of the Software.
  22. //
  23. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  27. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  28. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  29. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  30. //
  31. using System;
  32. using System.Collections;
  33. using System.Globalization;
  34. using System.IO;
  35. using System.Text;
  36. using System.Xml.XPath;
  37. using System.Diagnostics;
  38. using System.Xml.Schema;
  39. namespace System.Xml
  40. {
  41. public abstract class XmlNode : ICloneable, IEnumerable, IXPathNavigable
  42. {
  43. static EmptyNodeList emptyList = new EmptyNodeList ();
  44. class EmptyNodeList : XmlNodeList
  45. {
  46. static IEnumerator emptyEnumerator = new object [0].GetEnumerator ();
  47. public override int Count {
  48. get { return 0; }
  49. }
  50. public override IEnumerator GetEnumerator ()
  51. {
  52. return emptyEnumerator;
  53. }
  54. public override XmlNode Item (int index)
  55. {
  56. return null;
  57. }
  58. }
  59. #region Fields
  60. XmlDocument ownerDocument;
  61. XmlNode parentNode;
  62. XmlNodeListChildren childNodes;
  63. #endregion
  64. #region Constructors
  65. internal XmlNode (XmlDocument ownerDocument)
  66. {
  67. this.ownerDocument = ownerDocument;
  68. }
  69. #endregion
  70. #region Properties
  71. public virtual XmlAttributeCollection Attributes {
  72. get { return null; }
  73. }
  74. public virtual string BaseURI {
  75. get {
  76. // Isn't it conformant to W3C XML Base Recommendation?
  77. // As far as I tested, there are not...
  78. return (ParentNode != null) ? ParentNode.ChildrenBaseURI : String.Empty;
  79. }
  80. }
  81. internal virtual string ChildrenBaseURI {
  82. get {
  83. return BaseURI;
  84. }
  85. }
  86. public virtual XmlNodeList ChildNodes {
  87. get {
  88. IHasXmlChildNode l = this as IHasXmlChildNode;
  89. if (l == null)
  90. return emptyList;
  91. if (childNodes == null)
  92. childNodes = new XmlNodeListChildren (l);
  93. return childNodes;
  94. }
  95. }
  96. public virtual XmlNode FirstChild {
  97. get {
  98. IHasXmlChildNode l = this as IHasXmlChildNode;
  99. XmlLinkedNode c = (l == null) ?
  100. null : l.LastLinkedChild;
  101. return c == null ? null : c.NextLinkedSibling;
  102. }
  103. }
  104. public virtual bool HasChildNodes {
  105. get { return LastChild != null; }
  106. }
  107. public virtual string InnerText {
  108. get {
  109. switch (NodeType) {
  110. case XmlNodeType.Text:
  111. case XmlNodeType.CDATA:
  112. case XmlNodeType.SignificantWhitespace:
  113. case XmlNodeType.Whitespace:
  114. return Value;
  115. }
  116. if (FirstChild == null)
  117. return String.Empty;
  118. if (FirstChild == LastChild)
  119. return FirstChild.NodeType != XmlNodeType.Comment ?
  120. FirstChild.InnerText :
  121. String.Empty;
  122. StringBuilder builder = null;
  123. AppendChildValues (ref builder);
  124. return builder == null ? String.Empty : builder.ToString ();
  125. }
  126. set {
  127. if (! (this is XmlDocumentFragment))
  128. throw new InvalidOperationException ("This node is read only. Cannot be modified.");
  129. RemoveAll ();
  130. AppendChild (OwnerDocument.CreateTextNode (value));
  131. }
  132. }
  133. private void AppendChildValues (ref StringBuilder builder)
  134. {
  135. XmlNode node = FirstChild;
  136. while (node != null) {
  137. switch (node.NodeType) {
  138. case XmlNodeType.Text:
  139. case XmlNodeType.CDATA:
  140. case XmlNodeType.SignificantWhitespace:
  141. case XmlNodeType.Whitespace:
  142. if (builder == null)
  143. builder = new StringBuilder ();
  144. builder.Append (node.Value);
  145. break;
  146. }
  147. node.AppendChildValues (ref builder);
  148. node = node.NextSibling;
  149. }
  150. }
  151. public virtual string InnerXml {
  152. get {
  153. StringWriter sw = new StringWriter ();
  154. XmlTextWriter xtw = new XmlTextWriter (sw);
  155. WriteContentTo (xtw);
  156. return sw.GetStringBuilder ().ToString ();
  157. }
  158. set {
  159. throw new InvalidOperationException ("This node is readonly or doesn't have any children.");
  160. }
  161. }
  162. public virtual bool IsReadOnly {
  163. get
  164. {
  165. XmlNode curNode = this;
  166. do
  167. {
  168. switch (curNode.NodeType)
  169. {
  170. case XmlNodeType.EntityReference:
  171. case XmlNodeType.Entity:
  172. return true;
  173. case XmlNodeType.Attribute:
  174. curNode = ((XmlAttribute)curNode).OwnerElement;
  175. break;
  176. default:
  177. curNode = curNode.ParentNode;
  178. break;
  179. }
  180. }
  181. while (curNode != null) ;
  182. return false;
  183. }
  184. }
  185. [System.Runtime.CompilerServices.IndexerName("Item")]
  186. public virtual XmlElement this [string name] {
  187. get {
  188. for (int i = 0; i < ChildNodes.Count; i++) {
  189. XmlNode node = ChildNodes [i];
  190. if ((node.NodeType == XmlNodeType.Element) &&
  191. (node.Name == name)) {
  192. return (XmlElement) node;
  193. }
  194. }
  195. return null;
  196. }
  197. }
  198. [System.Runtime.CompilerServices.IndexerName("Item")]
  199. public virtual XmlElement this [string localname, string ns] {
  200. get {
  201. for (int i = 0; i < ChildNodes.Count; i++) {
  202. XmlNode node = ChildNodes [i];
  203. if ((node.NodeType == XmlNodeType.Element) &&
  204. (node.LocalName == localname) &&
  205. (node.NamespaceURI == ns)) {
  206. return (XmlElement) node;
  207. }
  208. }
  209. return null;
  210. }
  211. }
  212. public virtual XmlNode LastChild {
  213. get {
  214. IHasXmlChildNode l = this as IHasXmlChildNode;
  215. return l == null ? null : l.LastLinkedChild;
  216. }
  217. }
  218. public abstract string LocalName { get; }
  219. public abstract string Name { get; }
  220. public virtual string NamespaceURI {
  221. get { return String.Empty; }
  222. }
  223. public virtual XmlNode NextSibling {
  224. get { return null; }
  225. }
  226. public abstract XmlNodeType NodeType { get; }
  227. internal virtual XPathNodeType XPathNodeType {
  228. get {
  229. throw new InvalidOperationException ("Can not get XPath node type from " + this.GetType ().ToString ());
  230. }
  231. }
  232. public virtual string OuterXml {
  233. get {
  234. StringWriter sw = new StringWriter ();
  235. XmlTextWriter xtw = new XmlTextWriter (sw);
  236. WriteTo (xtw);
  237. return sw.ToString ();
  238. }
  239. }
  240. public virtual XmlDocument OwnerDocument {
  241. get { return ownerDocument; }
  242. }
  243. public virtual XmlNode ParentNode {
  244. get { return parentNode; }
  245. }
  246. public virtual string Prefix {
  247. get { return String.Empty; }
  248. set {}
  249. }
  250. public virtual XmlNode PreviousSibling {
  251. get { return null; }
  252. }
  253. public virtual string Value {
  254. get { return null; }
  255. set { throw new InvalidOperationException ("This node does not have a value"); }
  256. }
  257. internal virtual string XmlLang {
  258. get {
  259. if(Attributes != null)
  260. for (int i = 0; i < Attributes.Count; i++) {
  261. XmlAttribute attr = Attributes [i];
  262. if(attr.Name == "xml:lang")
  263. return attr.Value;
  264. }
  265. return (ParentNode != null) ? ParentNode.XmlLang : OwnerDocument.XmlLang;
  266. }
  267. }
  268. internal virtual XmlSpace XmlSpace {
  269. get {
  270. if(Attributes != null) {
  271. for (int i = 0; i < Attributes.Count; i++) {
  272. XmlAttribute attr = Attributes [i];
  273. if(attr.Name == "xml:space") {
  274. switch(attr.Value) {
  275. case "preserve": return XmlSpace.Preserve;
  276. case "default": return XmlSpace.Default;
  277. }
  278. break;
  279. }
  280. }
  281. }
  282. return (ParentNode != null) ? ParentNode.XmlSpace : OwnerDocument.XmlSpace;
  283. }
  284. }
  285. public virtual IXmlSchemaInfo SchemaInfo {
  286. get { return null; }
  287. internal set { }
  288. }
  289. #endregion
  290. #region Methods
  291. public virtual XmlNode AppendChild (XmlNode newChild)
  292. {
  293. // AppendChild(n) is equivalent to InsertBefore(n, null)
  294. return InsertBefore (newChild, null);
  295. }
  296. internal XmlNode AppendChild (XmlNode newChild, bool checkNodeType)
  297. {
  298. return InsertBefore (newChild, null, checkNodeType, true);
  299. }
  300. public virtual XmlNode Clone ()
  301. {
  302. // By MS document, it is equivalent to CloneNode(true).
  303. return this.CloneNode (true);
  304. }
  305. public abstract XmlNode CloneNode (bool deep);
  306. public virtual XPathNavigator CreateNavigator ()
  307. {
  308. // XmlDocument has overriden definition, so it is safe
  309. // to use OwnerDocument here.
  310. return OwnerDocument.CreateNavigator (this);
  311. }
  312. public IEnumerator GetEnumerator ()
  313. {
  314. return ChildNodes.GetEnumerator ();
  315. }
  316. public virtual string GetNamespaceOfPrefix (string prefix)
  317. {
  318. switch (prefix) {
  319. case null:
  320. throw new ArgumentNullException ("prefix");
  321. case "xml":
  322. return XmlNamespaceManager.XmlnsXml;
  323. case "xmlns":
  324. return XmlNamespaceManager.XmlnsXmlns;
  325. }
  326. XmlNode node;
  327. switch (NodeType) {
  328. case XmlNodeType.Attribute:
  329. node = ((XmlAttribute) this).OwnerElement;
  330. if (node == null)
  331. return String.Empty;
  332. break;
  333. case XmlNodeType.Element:
  334. node = this;
  335. break;
  336. default:
  337. node = ParentNode;
  338. break;
  339. }
  340. while (node != null) {
  341. if (node.Prefix == prefix)
  342. return node.NamespaceURI;
  343. if (node.NodeType == XmlNodeType.Element &&
  344. ((XmlElement) node).HasAttributes) {
  345. int count = node.Attributes.Count;
  346. for (int i = 0; i < count; i++) {
  347. XmlAttribute attr = node.Attributes [i];
  348. if (prefix == attr.LocalName && attr.Prefix == "xmlns"
  349. || attr.Name == "xmlns" && prefix == String.Empty)
  350. return attr.Value;
  351. }
  352. }
  353. node = node.ParentNode;
  354. }
  355. return String.Empty;
  356. }
  357. public virtual string GetPrefixOfNamespace (string namespaceURI)
  358. {
  359. switch (namespaceURI) {
  360. case XmlNamespaceManager.XmlnsXml:
  361. return XmlNamespaceManager.PrefixXml;
  362. case XmlNamespaceManager.XmlnsXmlns:
  363. return XmlNamespaceManager.PrefixXmlns;
  364. }
  365. XmlNode node;
  366. switch (NodeType) {
  367. case XmlNodeType.Attribute:
  368. node = ((XmlAttribute) this).OwnerElement;
  369. break;
  370. case XmlNodeType.Element:
  371. node = this;
  372. break;
  373. default:
  374. node = ParentNode;
  375. break;
  376. }
  377. while (node != null) {
  378. if (node.NodeType == XmlNodeType.Element &&
  379. ((XmlElement) node).HasAttributes) {
  380. for (int i = 0; i < node.Attributes.Count; i++) {
  381. XmlAttribute attr = node.Attributes [i];
  382. if (attr.Prefix == "xmlns" && attr.Value == namespaceURI)
  383. return attr.LocalName;
  384. else if (attr.Name == "xmlns" && attr.Value == namespaceURI)
  385. return String.Empty;
  386. }
  387. }
  388. node = node.ParentNode;
  389. }
  390. return String.Empty;
  391. }
  392. object ICloneable.Clone ()
  393. {
  394. return Clone ();
  395. }
  396. IEnumerator IEnumerable.GetEnumerator ()
  397. {
  398. return GetEnumerator ();
  399. }
  400. public virtual XmlNode InsertAfter (XmlNode newChild, XmlNode refChild)
  401. {
  402. // InsertAfter(n1, n2) is equivalent to InsertBefore(n1, n2.PreviousSibling).
  403. // I took this way because current implementation
  404. // Calling InsertBefore() in this method is faster than
  405. // the counterpart, since NextSibling is faster than
  406. // PreviousSibling (these children are forward-only list).
  407. XmlNode argNode = null;
  408. if (refChild != null)
  409. argNode = refChild.NextSibling;
  410. else if (FirstChild != null)
  411. argNode = FirstChild;
  412. return InsertBefore (newChild, argNode);
  413. }
  414. public virtual XmlNode InsertBefore (XmlNode newChild, XmlNode refChild)
  415. {
  416. return InsertBefore (newChild, refChild, true, true);
  417. }
  418. // check for the node to be one of node ancestors
  419. internal bool IsAncestor (XmlNode newChild)
  420. {
  421. XmlNode currNode = this.ParentNode;
  422. while(currNode != null)
  423. {
  424. if(currNode == newChild)
  425. return true;
  426. currNode = currNode.ParentNode;
  427. }
  428. return false;
  429. }
  430. internal XmlNode InsertBefore (XmlNode newChild, XmlNode refChild, bool checkNodeType, bool raiseEvent)
  431. {
  432. if (checkNodeType)
  433. CheckNodeInsertion (newChild, refChild);
  434. if (newChild == refChild)
  435. return newChild;
  436. IHasXmlChildNode l = (IHasXmlChildNode) this;
  437. XmlDocument ownerDoc = (NodeType == XmlNodeType.Document) ? (XmlDocument) this : OwnerDocument;
  438. if (raiseEvent)
  439. ownerDoc.onNodeInserting (newChild, this);
  440. if (newChild.ParentNode != null)
  441. newChild.ParentNode.RemoveChild (newChild, checkNodeType);
  442. if (newChild.NodeType == XmlNodeType.DocumentFragment) {
  443. // This recursively invokes events. (It is compatible with MS implementation.)
  444. XmlNode ret = null;
  445. while (newChild.FirstChild != null) {
  446. var c = this.InsertBefore (newChild.FirstChild, refChild);
  447. ret = ret ?? c;
  448. }
  449. return ret;
  450. } else {
  451. XmlLinkedNode newLinkedChild = (XmlLinkedNode) newChild;
  452. newLinkedChild.parentNode = this;
  453. if (refChild == null) {
  454. // newChild is the last child:
  455. // * set newChild as NextSibling of the existing lastchild
  456. // * set LastChild = newChild
  457. // * set NextSibling of newChild as FirstChild
  458. if (l.LastLinkedChild != null) {
  459. XmlLinkedNode formerFirst = (XmlLinkedNode) FirstChild;
  460. l.LastLinkedChild.NextLinkedSibling = newLinkedChild;
  461. l.LastLinkedChild = newLinkedChild;
  462. newLinkedChild.NextLinkedSibling = formerFirst;
  463. } else {
  464. l.LastLinkedChild = newLinkedChild;
  465. l.LastLinkedChild.NextLinkedSibling = newLinkedChild; // FirstChild
  466. }
  467. } else {
  468. // newChild is not the last child:
  469. // * if newchild is first, then set next of lastchild is newChild.
  470. // otherwise, set next of previous sibling to newChild
  471. // * set next of newChild to refChild
  472. XmlLinkedNode prev = refChild.PreviousSibling as XmlLinkedNode;
  473. if (prev == null)
  474. l.LastLinkedChild.NextLinkedSibling = newLinkedChild;
  475. else
  476. prev.NextLinkedSibling = newLinkedChild;
  477. newLinkedChild.NextLinkedSibling = refChild as XmlLinkedNode;
  478. }
  479. switch (newChild.NodeType) {
  480. case XmlNodeType.EntityReference:
  481. ((XmlEntityReference) newChild).SetReferencedEntityContent ();
  482. break;
  483. case XmlNodeType.Entity:
  484. break;
  485. case XmlNodeType.DocumentType:
  486. break;
  487. }
  488. if (raiseEvent)
  489. ownerDoc.onNodeInserted (newChild, newChild.ParentNode);
  490. return newChild;
  491. }
  492. }
  493. private void CheckNodeInsertion (XmlNode newChild, XmlNode refChild)
  494. {
  495. XmlDocument ownerDoc = (NodeType == XmlNodeType.Document) ? (XmlDocument) this : OwnerDocument;
  496. if (NodeType != XmlNodeType.Element &&
  497. NodeType != XmlNodeType.Attribute &&
  498. NodeType != XmlNodeType.Document &&
  499. NodeType != XmlNodeType.DocumentFragment)
  500. throw new InvalidOperationException (String.Format ("Node cannot be appended to current node {0}.", NodeType));
  501. switch (NodeType) {
  502. case XmlNodeType.Attribute:
  503. switch (newChild.NodeType) {
  504. case XmlNodeType.Text:
  505. case XmlNodeType.EntityReference:
  506. break;
  507. default:
  508. throw new InvalidOperationException (String.Format (
  509. "Cannot insert specified type of node {0} as a child of this node {1}.",
  510. newChild.NodeType, NodeType));
  511. }
  512. break;
  513. case XmlNodeType.Element:
  514. switch (newChild.NodeType) {
  515. case XmlNodeType.Attribute:
  516. case XmlNodeType.Document:
  517. case XmlNodeType.DocumentType:
  518. case XmlNodeType.Entity:
  519. case XmlNodeType.Notation:
  520. case XmlNodeType.XmlDeclaration:
  521. throw new InvalidOperationException ("Cannot insert specified type of node as a child of this node.");
  522. }
  523. break;
  524. }
  525. if (IsReadOnly)
  526. throw new InvalidOperationException ("The node is readonly.");
  527. if (newChild.OwnerDocument != ownerDoc)
  528. throw new ArgumentException ("Can't append a node created by another document.");
  529. if (refChild != null) {
  530. if (refChild.ParentNode != this)
  531. throw new ArgumentException ("The reference node is not a child of this node.");
  532. }
  533. if(this == ownerDoc && ownerDoc.DocumentElement != null && (newChild is XmlElement) && newChild != ownerDoc.DocumentElement)
  534. throw new XmlException ("multiple document element not allowed.");
  535. // checking validity finished. then appending...
  536. if (newChild == this || IsAncestor (newChild))
  537. throw new ArgumentException("Cannot insert a node or any ancestor of that node as a child of itself.");
  538. }
  539. public virtual void Normalize ()
  540. {
  541. StringBuilder tmpBuilder = new StringBuilder ();
  542. int count = this.ChildNodes.Count;
  543. int start = 0;
  544. for (int i = 0; i < count; i++) {
  545. XmlNode c = ChildNodes [i];
  546. switch (c.NodeType) {
  547. case XmlNodeType.Text:
  548. case XmlNodeType.Whitespace:
  549. case XmlNodeType.SignificantWhitespace:
  550. tmpBuilder.Append (c.Value);
  551. break;
  552. default:
  553. c.Normalize ();
  554. NormalizeRange (start, i, tmpBuilder);
  555. // Continue to normalize from next node.
  556. start = i + 1;
  557. break;
  558. }
  559. }
  560. if (start < count) {
  561. NormalizeRange (start, count, tmpBuilder);
  562. }
  563. }
  564. private void NormalizeRange (int start, int i, StringBuilder tmpBuilder)
  565. {
  566. int keepPos = -1;
  567. // If Texts and Whitespaces are mixed, Text takes precedence to remain.
  568. // i.e. Whitespace should be removed.
  569. for (int j = start; j < i; j++) {
  570. XmlNode keep = ChildNodes [j];
  571. if (keep.NodeType == XmlNodeType.Text) {
  572. keepPos = j;
  573. break;
  574. }
  575. else if (keep.NodeType == XmlNodeType.SignificantWhitespace)
  576. keepPos = j;
  577. // but don't break up to find Text nodes.
  578. }
  579. if (keepPos >= 0) {
  580. for (int del = start; del < keepPos; del++)
  581. RemoveChild (ChildNodes [start]);
  582. int rest = i - keepPos - 1;
  583. for (int del = 0; del < rest; del++) {
  584. RemoveChild (ChildNodes [start + 1]);
  585. }
  586. }
  587. if (keepPos >= 0)
  588. ChildNodes [start].Value = tmpBuilder.ToString ();
  589. // otherwise nothing to be normalized
  590. tmpBuilder.Length = 0;
  591. }
  592. public virtual XmlNode PrependChild (XmlNode newChild)
  593. {
  594. return InsertAfter (newChild, null);
  595. }
  596. public virtual void RemoveAll ()
  597. {
  598. if (Attributes != null)
  599. Attributes.RemoveAll ();
  600. XmlNode next = null;
  601. for (XmlNode node = FirstChild; node != null; node = next) {
  602. next = node.NextSibling;
  603. RemoveChild (node);
  604. }
  605. }
  606. public virtual XmlNode RemoveChild (XmlNode oldChild)
  607. {
  608. return RemoveChild (oldChild, true);
  609. }
  610. private void CheckNodeRemoval ()
  611. {
  612. if (NodeType != XmlNodeType.Attribute &&
  613. NodeType != XmlNodeType.Element &&
  614. NodeType != XmlNodeType.Document &&
  615. NodeType != XmlNodeType.DocumentFragment)
  616. throw new ArgumentException (String.Format ("This {0} node cannot remove its child.", NodeType));
  617. if (IsReadOnly)
  618. throw new ArgumentException (String.Format ("This {0} node is read only.", NodeType));
  619. }
  620. internal XmlNode RemoveChild (XmlNode oldChild, bool checkNodeType)
  621. {
  622. if (oldChild == null)
  623. throw new NullReferenceException ();
  624. XmlDocument ownerDoc = (NodeType == XmlNodeType.Document) ? (XmlDocument)this : OwnerDocument;
  625. if(oldChild.ParentNode != this)
  626. throw new ArgumentException ("The node to be removed is not a child of this node.");
  627. if (checkNodeType)
  628. ownerDoc.onNodeRemoving (oldChild, oldChild.ParentNode);
  629. if (checkNodeType)
  630. CheckNodeRemoval ();
  631. IHasXmlChildNode l = (IHasXmlChildNode) this;
  632. if (Object.ReferenceEquals (l.LastLinkedChild, l.LastLinkedChild.NextLinkedSibling) && Object.ReferenceEquals (l.LastLinkedChild, oldChild))
  633. // If there is only one children, simply clear.
  634. l.LastLinkedChild = null;
  635. else {
  636. XmlLinkedNode oldLinkedChild = (XmlLinkedNode) oldChild;
  637. XmlLinkedNode beforeLinkedChild = l.LastLinkedChild;
  638. XmlLinkedNode firstChild = (XmlLinkedNode) FirstChild;
  639. while (Object.ReferenceEquals (beforeLinkedChild.NextLinkedSibling, l.LastLinkedChild) == false &&
  640. Object.ReferenceEquals (beforeLinkedChild.NextLinkedSibling, oldLinkedChild) == false)
  641. beforeLinkedChild = beforeLinkedChild.NextLinkedSibling;
  642. if (Object.ReferenceEquals (beforeLinkedChild.NextLinkedSibling, oldLinkedChild) == false)
  643. throw new ArgumentException ();
  644. beforeLinkedChild.NextLinkedSibling = oldLinkedChild.NextLinkedSibling;
  645. // Each derived class may have its own l.LastLinkedChild, so we must set it explicitly.
  646. if (oldLinkedChild.NextLinkedSibling == firstChild)
  647. l.LastLinkedChild = beforeLinkedChild;
  648. oldLinkedChild.NextLinkedSibling = null;
  649. }
  650. if (checkNodeType)
  651. ownerDoc.onNodeRemoved (oldChild, oldChild.ParentNode);
  652. oldChild.parentNode = null; // clear parent 'after' above logic.
  653. return oldChild;
  654. }
  655. public virtual XmlNode ReplaceChild (XmlNode newChild, XmlNode oldChild)
  656. {
  657. if(oldChild.ParentNode != this)
  658. throw new ArgumentException ("The node to be removed is not a child of this node.");
  659. if (newChild == this || IsAncestor (newChild))
  660. throw new InvalidOperationException("Cannot insert a node or any ancestor of that node as a child of itself.");
  661. XmlNode next = oldChild.NextSibling;
  662. RemoveChild (oldChild);
  663. InsertBefore (newChild, next);
  664. return oldChild;
  665. }
  666. // WARNING: don't use this member outside XmlAttribute nodes.
  667. internal XmlElement AttributeOwnerElement {
  668. get { return (XmlElement) parentNode; }
  669. set { parentNode = value; }
  670. }
  671. internal void SearchDescendantElements (string name, bool matchAll, ArrayList list)
  672. {
  673. for (XmlNode n = FirstChild; n != null; n = n.NextSibling) {
  674. if (n.NodeType != XmlNodeType.Element)
  675. continue;
  676. if (matchAll || n.Name == name)
  677. list.Add (n);
  678. n.SearchDescendantElements (name, matchAll, list);
  679. }
  680. }
  681. internal void SearchDescendantElements (string name, bool matchAllName, string ns, bool matchAllNS, ArrayList list)
  682. {
  683. for (XmlNode n = FirstChild; n != null; n = n.NextSibling) {
  684. if (n.NodeType != XmlNodeType.Element)
  685. continue;
  686. if ((matchAllName || n.LocalName == name)
  687. && (matchAllNS || n.NamespaceURI == ns))
  688. list.Add (n);
  689. n.SearchDescendantElements (name, matchAllName, ns, matchAllNS, list);
  690. }
  691. }
  692. public XmlNodeList SelectNodes (string xpath)
  693. {
  694. return SelectNodes (xpath, null);
  695. }
  696. public XmlNodeList SelectNodes (string xpath, XmlNamespaceManager nsmgr)
  697. {
  698. XPathNavigator nav = CreateNavigator ();
  699. XPathExpression expr = nav.Compile (xpath);
  700. if (nsmgr != null)
  701. expr.SetContext (nsmgr);
  702. XPathNodeIterator iter = nav.Select (expr);
  703. /*
  704. ArrayList rgNodes = new ArrayList ();
  705. while (iter.MoveNext ())
  706. {
  707. rgNodes.Add (((IHasXmlNode) iter.Current).GetNode ());
  708. }
  709. return new XmlNodeArrayList (rgNodes);
  710. */
  711. return new XmlIteratorNodeList (this as XmlDocument ?? ownerDocument, iter);
  712. }
  713. public XmlNode SelectSingleNode (string xpath)
  714. {
  715. return SelectSingleNode (xpath, null);
  716. }
  717. public XmlNode SelectSingleNode (string xpath, XmlNamespaceManager nsmgr)
  718. {
  719. XPathNavigator nav = CreateNavigator ();
  720. XPathExpression expr = nav.Compile (xpath);
  721. if (nsmgr != null)
  722. expr.SetContext (nsmgr);
  723. XPathNodeIterator iter = nav.Select (expr);
  724. if (!iter.MoveNext ())
  725. return null;
  726. return (iter.Current as IHasXmlNode).GetNode ();
  727. }
  728. public virtual bool Supports (string feature, string version)
  729. {
  730. if (String.Compare (feature, "xml", true, CultureInfo.InvariantCulture) == 0 // not case-sensitive
  731. && (String.Compare (version, "1.0", true, CultureInfo.InvariantCulture) == 0
  732. || String.Compare (version, "2.0", true, CultureInfo.InvariantCulture) == 0))
  733. return true;
  734. else
  735. return false;
  736. }
  737. public abstract void WriteContentTo (XmlWriter w);
  738. public abstract void WriteTo (XmlWriter w);
  739. // It parses this and all the ancestor elements,
  740. // find 'xmlns' declarations, stores and then return them.
  741. internal XmlNamespaceManager ConstructNamespaceManager ()
  742. {
  743. XmlDocument doc = this is XmlDocument ? (XmlDocument)this : this.OwnerDocument;
  744. XmlNamespaceManager nsmgr = new XmlNamespaceManager (doc.NameTable);
  745. XmlElement el = null;
  746. switch(this.NodeType) {
  747. case XmlNodeType.Attribute:
  748. el = ((XmlAttribute)this).OwnerElement;
  749. break;
  750. case XmlNodeType.Element:
  751. el = this as XmlElement;
  752. break;
  753. default:
  754. el = this.ParentNode as XmlElement;
  755. break;
  756. }
  757. while (el != null) {
  758. for (int i = 0; i < el.Attributes.Count; i++) {
  759. XmlAttribute attr = el.Attributes [i];
  760. if(attr.Prefix == "xmlns") {
  761. if (nsmgr.LookupNamespace (attr.LocalName) != attr.Value)
  762. nsmgr.AddNamespace (attr.LocalName, attr.Value);
  763. } else if(attr.Name == "xmlns") {
  764. if(nsmgr.LookupNamespace (String.Empty) != attr.Value)
  765. nsmgr.AddNamespace (String.Empty, attr.Value);
  766. }
  767. }
  768. // When reached to document, then it will set null value :)
  769. el = el.ParentNode as XmlElement;
  770. }
  771. return nsmgr;
  772. }
  773. #endregion
  774. }
  775. }