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