XPathDocumentIterator.cs 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. //------------------------------------------------------------------------------
  2. // <copyright file="XPathDocumentIterator.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. // <owner current="true" primary="true">Microsoft</owner>
  6. //------------------------------------------------------------------------------
  7. using System;
  8. using System.Xml;
  9. using System.Xml.XPath;
  10. using System.Diagnostics;
  11. namespace MS.Internal.Xml.Cache {
  12. /// <summary>
  13. /// Base internal class of all XPathDocument XPathNodeIterator implementations.
  14. /// </summary>
  15. internal abstract class XPathDocumentBaseIterator : XPathNodeIterator {
  16. protected XPathDocumentNavigator ctxt;
  17. protected int pos;
  18. /// <summary>
  19. /// Create a new iterator that is initially positioned on the "ctxt" node.
  20. /// </summary>
  21. protected XPathDocumentBaseIterator(XPathDocumentNavigator ctxt) {
  22. this.ctxt = new XPathDocumentNavigator(ctxt);
  23. }
  24. /// <summary>
  25. /// Create a new iterator that is a copy of "iter".
  26. /// </summary>
  27. protected XPathDocumentBaseIterator(XPathDocumentBaseIterator iter) {
  28. this.ctxt = new XPathDocumentNavigator(iter.ctxt);
  29. this.pos = iter.pos;
  30. }
  31. /// <summary>
  32. /// Return the current navigator.
  33. /// </summary>
  34. public override XPathNavigator Current {
  35. get { return this.ctxt; }
  36. }
  37. /// <summary>
  38. /// Return the iterator's current position.
  39. /// </summary>
  40. public override int CurrentPosition {
  41. get { return this.pos; }
  42. }
  43. }
  44. /// <summary>
  45. /// Iterate over all element children with a particular QName.
  46. /// </summary>
  47. internal class XPathDocumentElementChildIterator : XPathDocumentBaseIterator {
  48. private string localName, namespaceUri;
  49. /// <summary>
  50. /// Create an iterator that ranges over all element children of "parent" having the specified QName.
  51. /// </summary>
  52. public XPathDocumentElementChildIterator(XPathDocumentNavigator parent, string name, string namespaceURI) : base(parent) {
  53. if (namespaceURI == null) throw new ArgumentNullException("namespaceURI");
  54. this.localName = parent.NameTable.Get(name);
  55. this.namespaceUri = namespaceURI;
  56. }
  57. /// <summary>
  58. /// Create a new iterator that is a copy of "iter".
  59. /// </summary>
  60. public XPathDocumentElementChildIterator(XPathDocumentElementChildIterator iter) : base(iter) {
  61. this.localName = iter.localName;
  62. this.namespaceUri = iter.namespaceUri;
  63. }
  64. /// <summary>
  65. /// Create a copy of this iterator.
  66. /// </summary>
  67. public override XPathNodeIterator Clone() {
  68. return new XPathDocumentElementChildIterator(this);
  69. }
  70. /// <summary>
  71. /// Position the iterator to the next matching child.
  72. /// </summary>
  73. public override bool MoveNext() {
  74. if (this.pos == 0) {
  75. if (!this.ctxt.MoveToChild(this.localName, this.namespaceUri))
  76. return false;
  77. }
  78. else {
  79. if (!this.ctxt.MoveToNext(this.localName, this.namespaceUri))
  80. return false;
  81. }
  82. this.pos++;
  83. return true;
  84. }
  85. }
  86. /// <summary>
  87. /// Iterate over all content children with a particular XPathNodeType.
  88. /// </summary>
  89. internal class XPathDocumentKindChildIterator : XPathDocumentBaseIterator {
  90. private XPathNodeType typ;
  91. /// <summary>
  92. /// Create an iterator that ranges over all content children of "parent" having the specified XPathNodeType.
  93. /// </summary>
  94. public XPathDocumentKindChildIterator(XPathDocumentNavigator parent, XPathNodeType typ) : base(parent) {
  95. this.typ = typ;
  96. }
  97. /// <summary>
  98. /// Create a new iterator that is a copy of "iter".
  99. /// </summary>
  100. public XPathDocumentKindChildIterator(XPathDocumentKindChildIterator iter) : base(iter) {
  101. this.typ = iter.typ;
  102. }
  103. /// <summary>
  104. /// Create a copy of this iterator.
  105. /// </summary>
  106. public override XPathNodeIterator Clone() {
  107. return new XPathDocumentKindChildIterator(this);
  108. }
  109. /// <summary>
  110. /// Position the iterator to the next descendant.
  111. /// </summary>
  112. public override bool MoveNext() {
  113. if (this.pos == 0) {
  114. if (!this.ctxt.MoveToChild(this.typ))
  115. return false;
  116. }
  117. else {
  118. if (!this.ctxt.MoveToNext(this.typ))
  119. return false;
  120. }
  121. this.pos++;
  122. return true;
  123. }
  124. }
  125. /// <summary>
  126. /// Iterate over all element descendants with a particular QName.
  127. /// </summary>
  128. internal class XPathDocumentElementDescendantIterator : XPathDocumentBaseIterator {
  129. private XPathDocumentNavigator end;
  130. private string localName, namespaceUri;
  131. private bool matchSelf;
  132. /// <summary>
  133. /// Create an iterator that ranges over all element descendants of "root" having the specified QName.
  134. /// </summary>
  135. public XPathDocumentElementDescendantIterator(XPathDocumentNavigator root, string name, string namespaceURI, bool matchSelf) : base(root) {
  136. if (namespaceURI == null) throw new ArgumentNullException("namespaceURI");
  137. this.localName = root.NameTable.Get(name);
  138. this.namespaceUri = namespaceURI;
  139. this.matchSelf = matchSelf;
  140. // Find the next non-descendant node that follows "root" in document order
  141. if (root.NodeType != XPathNodeType.Root) {
  142. this.end = new XPathDocumentNavigator(root);
  143. this.end.MoveToNonDescendant();
  144. }
  145. }
  146. /// <summary>
  147. /// Create a new iterator that is a copy of "iter".
  148. /// </summary>
  149. public XPathDocumentElementDescendantIterator(XPathDocumentElementDescendantIterator iter) : base(iter) {
  150. this.end = iter.end;
  151. this.localName = iter.localName;
  152. this.namespaceUri = iter.namespaceUri;
  153. this.matchSelf = iter.matchSelf;
  154. }
  155. /// <summary>
  156. /// Create a copy of this iterator.
  157. /// </summary>
  158. public override XPathNodeIterator Clone() {
  159. return new XPathDocumentElementDescendantIterator(this);
  160. }
  161. /// <summary>
  162. /// Position the iterator to the next descendant.
  163. /// </summary>
  164. public override bool MoveNext() {
  165. if (this.matchSelf) {
  166. this.matchSelf = false;
  167. if (this.ctxt.IsElementMatch(this.localName, this.namespaceUri)) {
  168. this.pos++;
  169. return true;
  170. }
  171. }
  172. if (!this.ctxt.MoveToFollowing(this.localName, this.namespaceUri, this.end))
  173. return false;
  174. this.pos++;
  175. return true;
  176. }
  177. }
  178. /// <summary>
  179. /// Iterate over all content descendants with a particular XPathNodeType.
  180. /// </summary>
  181. internal class XPathDocumentKindDescendantIterator : XPathDocumentBaseIterator {
  182. private XPathDocumentNavigator end;
  183. private XPathNodeType typ;
  184. private bool matchSelf;
  185. /// <summary>
  186. /// Create an iterator that ranges over all content descendants of "root" having the specified XPathNodeType.
  187. /// </summary>
  188. public XPathDocumentKindDescendantIterator(XPathDocumentNavigator root, XPathNodeType typ, bool matchSelf) : base(root) {
  189. this.typ = typ;
  190. this.matchSelf = matchSelf;
  191. // Find the next non-descendant node that follows "root" in document order
  192. if (root.NodeType != XPathNodeType.Root) {
  193. this.end = new XPathDocumentNavigator(root);
  194. this.end.MoveToNonDescendant();
  195. }
  196. }
  197. /// <summary>
  198. /// Create a new iterator that is a copy of "iter".
  199. /// </summary>
  200. public XPathDocumentKindDescendantIterator(XPathDocumentKindDescendantIterator iter) : base(iter) {
  201. this.end = iter.end;
  202. this.typ = iter.typ;
  203. this.matchSelf = iter.matchSelf;
  204. }
  205. /// <summary>
  206. /// Create a copy of this iterator.
  207. /// </summary>
  208. public override XPathNodeIterator Clone() {
  209. return new XPathDocumentKindDescendantIterator(this);
  210. }
  211. /// <summary>
  212. /// Position the iterator to the next descendant.
  213. /// </summary>
  214. public override bool MoveNext() {
  215. if (this.matchSelf) {
  216. this.matchSelf = false;
  217. if (this.ctxt.IsKindMatch(this.typ)) {
  218. this.pos++;
  219. return true;
  220. }
  221. }
  222. if (!this.ctxt.MoveToFollowing(this.typ, this.end))
  223. return false;
  224. this.pos++;
  225. return true;
  226. }
  227. }
  228. }