1 //------------------------------------------------------------------------------
2 // <copyright file="TreeIterators.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
8 using System.ComponentModel;
9 using System.Diagnostics;
10 using System.Xml.XPath;
12 namespace System.Xml.Xsl.Runtime {
15 /// Iterate over all descendant content nodes according to XPath descendant axis rules.
17 [EditorBrowsable(EditorBrowsableState.Never)]
18 public struct DescendantIterator {
19 private XmlNavigatorFilter filter;
20 private XPathNavigator navCurrent, navEnd;
21 private bool hasFirst;
24 /// Initialize the DescendantIterator (no possibility of duplicates).
26 public void Create(XPathNavigator input, XmlNavigatorFilter filter, bool orSelf) {
27 // Save input node as current node
28 this.navCurrent = XmlQueryRuntime.SyncToNavigator(this.navCurrent, input);
31 // Position navEnd to the node at which the descendant scan should terminate
32 if (input.NodeType == XPathNodeType.Root) {
36 this.navEnd = XmlQueryRuntime.SyncToNavigator(this.navEnd, input);
37 this.navEnd.MoveToNonDescendant();
40 // If self node matches, then return it first
41 this.hasFirst = (orSelf && !this.filter.IsFiltered(this.navCurrent));
45 /// Position this iterator to the next descendant node. Return false if there are no more descendant nodes.
46 /// Return true if the Current property is set to the next node in the iteration.
48 public bool MoveNext() {
50 this.hasFirst = false;
53 return (this.filter.MoveToFollowing(this.navCurrent, this.navEnd));
57 /// Return the current result navigator. This is only defined after MoveNext() has returned true.
59 public XPathNavigator Current {
60 get { return this.navCurrent; }
66 /// Iterate over all descendant content nodes according to XPath descendant axis rules. Eliminate duplicates by not
67 /// querying over nodes that are contained in the subtree of the previous node.
69 [EditorBrowsable(EditorBrowsableState.Never)]
70 public struct DescendantMergeIterator {
71 private XmlNavigatorFilter filter;
72 private XPathNavigator navCurrent, navRoot, navEnd;
73 private IteratorState state;
76 private enum IteratorState {
83 /// Initialize the DescendantIterator (merge multiple sets of descendant nodes in document order and remove duplicates).
85 public void Create(XmlNavigatorFilter filter, bool orSelf) {
87 this.state = IteratorState.NoPrevious;
92 /// Position this iterator to the next descendant node. Return IteratorResult.NoMoreNodes if there are no more
93 /// descendant nodes. Return IteratorResult.NeedInputNode if the next input node needs to be fetched.
94 /// Return IteratorResult.HaveCurrent if the Current property is set to the next node in the iteration.
96 public IteratorResult MoveNext(XPathNavigator input) {
97 if (this.state != IteratorState.NeedDescendant) {
99 return IteratorResult.NoMoreNodes;
101 // Descendants of the input node will be duplicates if the input node is in the subtree
102 // of the previous root.
103 if (this.state != IteratorState.NoPrevious && this.navRoot.IsDescendant(input))
104 return IteratorResult.NeedInputNode;
106 // Save input node as current node and end of input's tree in navEnd
107 this.navCurrent = XmlQueryRuntime.SyncToNavigator(this.navCurrent, input);
108 this.navRoot = XmlQueryRuntime.SyncToNavigator(this.navRoot, input);
109 this.navEnd = XmlQueryRuntime.SyncToNavigator(this.navEnd, input);
110 this.navEnd.MoveToNonDescendant();
112 this.state = IteratorState.NeedDescendant;
114 // If self node matches, then return it
115 if (this.orSelf && !this.filter.IsFiltered(input))
116 return IteratorResult.HaveCurrentNode;
119 if (this.filter.MoveToFollowing(this.navCurrent, this.navEnd))
120 return IteratorResult.HaveCurrentNode;
122 // No more descendants, so transition to NeedCurrent state and get the next input node
123 this.state = IteratorState.NeedCurrent;
124 return IteratorResult.NeedInputNode;
128 /// Return the current result navigator. This is only defined after MoveNext() has returned true or IteratorResult.HaveCurrentNode.
130 public XPathNavigator Current {
131 get { return this.navCurrent; }
137 /// Iterate over matching parent node according to XPath parent axis rules.
139 [EditorBrowsable(EditorBrowsableState.Never)]
140 public struct ParentIterator {
141 private XPathNavigator navCurrent;
142 private bool haveCurrent;
145 /// Initialize the ParentIterator.
147 public void Create(XPathNavigator context, XmlNavigatorFilter filter) {
148 // Save context node as current node
149 this.navCurrent = XmlQueryRuntime.SyncToNavigator(this.navCurrent, context);
151 // Attempt to find a matching parent node
152 this.haveCurrent = (this.navCurrent.MoveToParent()) && (!filter.IsFiltered(this.navCurrent));
156 /// Return true if a matching parent node exists and set Current property. Otherwise, return false
157 /// (Current property is undefined).
159 public bool MoveNext() {
160 if (this.haveCurrent) {
161 this.haveCurrent = false;
165 // Iteration is complete
170 /// Return the current result navigator. This is only defined after MoveNext() has returned true.
172 public XPathNavigator Current {
173 get { return this.navCurrent; }
179 /// Iterate over all ancestor nodes according to XPath ancestor axis rules, returning nodes in reverse
182 [EditorBrowsable(EditorBrowsableState.Never)]
183 public struct AncestorIterator {
184 private XmlNavigatorFilter filter;
185 private XPathNavigator navCurrent;
186 private bool haveCurrent;
189 /// Initialize the AncestorIterator.
191 public void Create(XPathNavigator context, XmlNavigatorFilter filter, bool orSelf) {
192 this.filter = filter;
194 // Save context node as current node
195 this.navCurrent = XmlQueryRuntime.SyncToNavigator(this.navCurrent, context);
197 // If self node matches, then next call to MoveNext() should return it
198 // Otherwise, MoveNext() will fetch next ancestor
199 this.haveCurrent = (orSelf && !this.filter.IsFiltered(this.navCurrent));
203 /// Position the iterator on the next matching ancestor node. Return true if such a node exists and
204 /// set Current property. Otherwise, return false (Current property is undefined).
206 public bool MoveNext() {
207 if (this.haveCurrent) {
208 this.haveCurrent = false;
212 while (this.navCurrent.MoveToParent()) {
213 if (!this.filter.IsFiltered(this.navCurrent))
217 // Iteration is complete
222 /// Return the current result navigator. This is only defined after MoveNext() has returned true.
224 public XPathNavigator Current {
225 get { return this.navCurrent; }
231 /// Iterate over all ancestor nodes according to XPath ancestor axis rules, but return the nodes in document order.
233 [EditorBrowsable(EditorBrowsableState.Never)]
234 public struct AncestorDocOrderIterator {
235 private XmlNavigatorStack stack;
236 private XPathNavigator navCurrent;
239 /// Initialize the AncestorDocOrderIterator (return ancestor nodes in document order, no possibility of duplicates).
241 public void Create(XPathNavigator context, XmlNavigatorFilter filter, bool orSelf) {
242 AncestorIterator wrapped = new AncestorIterator();
243 wrapped.Create(context, filter, orSelf);
246 // Fetch all ancestor nodes in reverse document order and push them onto the stack
247 while (wrapped.MoveNext())
248 this.stack.Push(wrapped.Current.Clone());
252 /// Return true if the Current property is set to the next Ancestor node in document order.
254 public bool MoveNext() {
255 if (this.stack.IsEmpty)
258 this.navCurrent = this.stack.Pop();
263 /// Return the current result navigator. This is only defined after MoveNext() has returned true.
265 public XPathNavigator Current {
266 get { return this.navCurrent; }
272 /// Iterate over all following nodes according to XPath following axis rules. These rules specify that
273 /// descendants are not included, even though they follow the starting node in document order. For the
274 /// "true" following axis, see FollowingIterator.
276 [EditorBrowsable(EditorBrowsableState.Never)]
277 public struct XPathFollowingIterator {
278 private XmlNavigatorFilter filter;
279 private XPathNavigator navCurrent;
283 /// Initialize the XPathFollowingIterator (no possibility of duplicates).
285 public void Create(XPathNavigator input, XmlNavigatorFilter filter) {
286 // Save input node as current node
287 this.navCurrent = XmlQueryRuntime.SyncToNavigator(this.navCurrent, input);
288 this.filter = filter;
289 this.needFirst = true;
293 /// Position this iterator to the next following node. Return false if there are no more following nodes.
294 /// Return true if the Current property is set to the next node in the iteration.
296 public bool MoveNext() {
297 if (this.needFirst) {
298 if (!MoveFirst(this.filter, this.navCurrent))
301 this.needFirst = false;
305 return this.filter.MoveToFollowing(this.navCurrent, null);
309 /// Return the current result navigator. This is only defined after MoveNext() has returned true.
311 public XPathNavigator Current {
312 get { return this.navCurrent; }
316 /// Position "nav" to the matching node which follows it in document order but is not a descendant node.
317 /// Return false if this is no such matching node.
319 internal static bool MoveFirst(XmlNavigatorFilter filter, XPathNavigator nav) {
320 // Attributes and namespace nodes include descendants of their owner element in the set of following nodes
321 if (nav.NodeType == XPathNodeType.Attribute || nav.NodeType == XPathNodeType.Namespace) {
322 if (!nav.MoveToParent()) {
323 // Floating attribute or namespace node that has no following nodes
327 if (!filter.MoveToFollowing(nav, null)) {
328 // No matching following nodes
333 // XPath spec doesn't include descendants of the input node in the following axis
334 if (!nav.MoveToNonDescendant())
335 // No following nodes
338 // If the sibling does not match the node-test, find the next following node that does
339 if (filter.IsFiltered(nav)) {
340 if (!filter.MoveToFollowing(nav, null)) {
341 // No matching following nodes
354 /// Iterate over all following nodes according to XPath following axis rules. Merge multiple sets of following nodes
355 /// in document order and remove duplicates.
357 [EditorBrowsable(EditorBrowsableState.Never)]
358 public struct XPathFollowingMergeIterator {
359 private XmlNavigatorFilter filter;
360 private IteratorState state;
361 private XPathNavigator navCurrent, navNext;
363 private enum IteratorState {
364 NeedCandidateCurrent = 0,
365 HaveCandidateCurrent,
372 /// Initialize the XPathFollowingMergeIterator (merge multiple sets of following nodes in document order and remove duplicates).
374 public void Create(XmlNavigatorFilter filter) {
375 this.filter = filter;
376 this.state = IteratorState.NeedCandidateCurrent;
380 /// Position this iterator to the next following node. Prune by finding the first input node in
381 /// document order that has no other input nodes in its subtree. All other input nodes should be
382 /// discarded. Return IteratorResult.NeedInputNode if the next input node needs to be fetched
383 /// first. Return IteratorResult.HaveCurrent if the Current property is set to the next node in the
386 public IteratorResult MoveNext(XPathNavigator input) {
387 switch (this.state) {
388 case IteratorState.NeedCandidateCurrent:
389 // If there are no more input nodes, then iteration is complete
391 return IteratorResult.NoMoreNodes;
393 // Save input node as current node
394 this.navCurrent = XmlQueryRuntime.SyncToNavigator(this.navCurrent, input);
396 // Still must check next input node to see if is a descendant of this one
397 this.state = IteratorState.HaveCandidateCurrent;
398 return IteratorResult.NeedInputNode;
400 case IteratorState.HaveCandidateCurrent:
401 // If there are no more input nodes,
403 // Then candidate node has been selected, and there are no further input nodes
404 this.state = IteratorState.HaveCurrentNoNext;
408 // If input node is in the subtree of the candidate node, then use the input node instead
409 if (this.navCurrent.IsDescendant(input))
410 goto case IteratorState.NeedCandidateCurrent;
412 // Found node on which to perform following scan. Now skip past all input nodes in the same document.
413 this.state = IteratorState.HaveCurrentNeedNext;
414 goto case IteratorState.HaveCurrentNeedNext;
416 case IteratorState.HaveCurrentNeedNext:
417 // If there are no more input nodes,
419 // Then candidate node has been selected, and there are no further input nodes
420 this.state = IteratorState.HaveCurrentNoNext;
424 // Skip input node unless it's in a different document than the node on which the following scan was performed
425 if (this.navCurrent.ComparePosition(input) != XmlNodeOrder.Unknown)
426 return IteratorResult.NeedInputNode;
428 // Next node is in a different document, so save it
429 this.navNext = XmlQueryRuntime.SyncToNavigator(this.navNext, input);
430 this.state = IteratorState.HaveCurrentHaveNext;
434 if (!this.filter.MoveToFollowing(this.navCurrent, null))
437 return IteratorResult.HaveCurrentNode;
441 /// Return the current result navigator. This is only defined after MoveNext() has returned true or IteratorResult.HaveCurrentNode.
443 public XPathNavigator Current {
444 get { return this.navCurrent; }
448 /// Called when an attempt to move to a following node failed. If a Next node exists, then make that the new
449 /// candidate current node. Otherwise, iteration is complete.
451 private IteratorResult MoveFailed() {
452 XPathNavigator navTemp;
453 Debug.Assert(this.state == IteratorState.HaveCurrentHaveNext || this.state == IteratorState.HaveCurrentNoNext);
455 if (this.state == IteratorState.HaveCurrentNoNext) {
456 // No more nodes, so iteration is complete
457 this.state = IteratorState.NeedCandidateCurrent;
458 return IteratorResult.NoMoreNodes;
461 // Make next node the new candidate node
462 this.state = IteratorState.HaveCandidateCurrent;
464 // Swap navigators in order to sometimes avoid creating clones
465 navTemp = this.navCurrent;
466 this.navCurrent = this.navNext;
467 this.navNext = navTemp;
469 return IteratorResult.NeedInputNode;
473 /// Position this.navCurrent to the node which follows it in document order but is not a descendant node.
475 private IteratorResult MoveFirst() {
476 Debug.Assert(this.state == IteratorState.HaveCurrentHaveNext || this.state == IteratorState.HaveCurrentNoNext);
478 if (!XPathFollowingIterator.MoveFirst(this.filter, this.navCurrent))
481 return IteratorResult.HaveCurrentNode;
487 /// Iterate over all content-typed nodes which precede the starting node in document order. Return nodes
488 /// in reverse document order.
490 [EditorBrowsable(EditorBrowsableState.Never)]
491 public struct PrecedingIterator {
492 private XmlNavigatorStack stack;
493 private XPathNavigator navCurrent;
496 /// Initialize the PrecedingIterator (no possibility of duplicates).
498 public void Create(XPathNavigator context, XmlNavigatorFilter filter) {
499 // Start at root, which is always first node in the document
500 this.navCurrent = XmlQueryRuntime.SyncToNavigator(this.navCurrent, context);
501 this.navCurrent.MoveToRoot();
504 // If root node is not the ending node,
505 if (!this.navCurrent.IsSamePosition(context)) {
506 // Push root onto the stack if it is not filtered
507 if (!filter.IsFiltered(this.navCurrent))
508 this.stack.Push(this.navCurrent.Clone());
510 // Push all matching nodes onto stack
511 while (filter.MoveToFollowing(this.navCurrent, context))
512 this.stack.Push(this.navCurrent.Clone());
517 /// Return true if the Current property is set to the next Preceding node in reverse document order.
519 public bool MoveNext() {
520 if (this.stack.IsEmpty)
523 this.navCurrent = this.stack.Pop();
528 /// Return the current result navigator. This is only defined after MoveNext() has returned true.
530 public XPathNavigator Current {
531 get { return this.navCurrent; }
537 /// Iterate over all preceding nodes according to XPath preceding axis rules, returning nodes in reverse
538 /// document order. These rules specify that ancestors are not included, even though they precede the
539 /// starting node in document order. For the "true" preceding axis, see PrecedingIterator.
541 [EditorBrowsable(EditorBrowsableState.Never)]
542 public struct XPathPrecedingIterator {
543 private XmlNavigatorStack stack;
544 private XPathNavigator navCurrent;
547 /// Initialize the XPathPrecedingIterator (no possibility of duplicates).
549 public void Create(XPathNavigator context, XmlNavigatorFilter filter) {
550 XPathPrecedingDocOrderIterator wrapped = new XPathPrecedingDocOrderIterator();
551 wrapped.Create(context, filter);
554 // Fetch all preceding nodes in document order and push them onto the stack
555 while (wrapped.MoveNext())
556 this.stack.Push(wrapped.Current.Clone());
560 /// Return true if the Current property is set to the next Preceding node in reverse document order.
562 public bool MoveNext() {
563 if (this.stack.IsEmpty)
566 this.navCurrent = this.stack.Pop();
571 /// Return the current result navigator. This is only defined after MoveNext() has returned true.
573 public XPathNavigator Current {
574 get { return this.navCurrent; }
580 /// Iterate over all preceding nodes according to XPath preceding axis rules, returning nodes in document order.
582 [EditorBrowsable(EditorBrowsableState.Never)]
583 public struct XPathPrecedingDocOrderIterator {
584 private XmlNavigatorFilter filter;
585 private XPathNavigator navCurrent;
586 private XmlNavigatorStack navStack;
589 /// Initialize the XPathPrecedingDocOrderIterator (return preceding nodes in document order, no possibility of duplicates).
591 public void Create(XPathNavigator input, XmlNavigatorFilter filter) {
592 // Save input node as current node
593 this.navCurrent = XmlQueryRuntime.SyncToNavigator(this.navCurrent, input);
594 this.filter = filter;
599 /// Position this iterator to the next preceding node. Return false if there are no more preceding nodes.
600 /// Return true if the Current property is set to the next node in the iteration.
602 public bool MoveNext() {
603 if (!this.navStack.IsEmpty) {
605 // Move to the next matching node that is before the top node on the stack in document order
606 if (this.filter.MoveToFollowing(this.navCurrent, this.navStack.Peek()))
610 // Do not include ancestor nodes as part of the preceding axis
611 this.navCurrent.MoveTo(this.navStack.Pop());
613 // No more preceding matches possible
614 if (this.navStack.IsEmpty)
623 /// Return the current result navigator. This is only defined after MoveNext() has returned true or
624 /// IteratorResult.HaveCurrentNode.
626 public XPathNavigator Current {
627 get { return this.navCurrent; }
631 /// Push all ancestors of this.navCurrent onto a stack. The set of preceding nodes should not contain any of these
634 private void PushAncestors() {
635 this.navStack.Reset();
637 this.navStack.Push(this.navCurrent.Clone());
639 while (this.navCurrent.MoveToParent());
641 // Pop the root of the tree, since MoveToFollowing calls will never return it
648 /// Iterate over all preceding nodes according to XPath preceding axis rules, except that nodes are always
649 /// returned in document order. Merge multiple sets of preceding nodes in document order and remove duplicates.
651 [EditorBrowsable(EditorBrowsableState.Never)]
652 public struct XPathPrecedingMergeIterator {
653 private XmlNavigatorFilter filter;
654 private IteratorState state;
655 private XPathNavigator navCurrent, navNext;
656 private XmlNavigatorStack navStack;
658 private enum IteratorState {
659 NeedCandidateCurrent = 0,
660 HaveCandidateCurrent,
666 /// Initialize the XPathPrecedingMergeIterator (merge multiple sets of preceding nodes in document order and remove duplicates).
668 public void Create(XmlNavigatorFilter filter) {
669 this.filter = filter;
670 this.state = IteratorState.NeedCandidateCurrent;
674 /// Position this iterator to the next preceding node in document order. Discard all input nodes
675 /// that are followed by another input node in the same document. This leaves one node per document from
676 /// which the complete set of preceding nodes can be derived without possibility of duplicates.
677 /// Return IteratorResult.NeedInputNode if the next input node needs to be fetched first. Return
678 /// IteratorResult.HaveCurrent if the Current property is set to the next node in the iteration.
680 public IteratorResult MoveNext(XPathNavigator input) {
681 switch (this.state) {
682 case IteratorState.NeedCandidateCurrent:
683 // If there are no more input nodes, then iteration is complete
685 return IteratorResult.NoMoreNodes;
687 // Save input node as current node
688 this.navCurrent = XmlQueryRuntime.SyncToNavigator(this.navCurrent, input);
690 // Scan for additional input nodes within the same document (since they are after navCurrent in docorder)
691 this.state = IteratorState.HaveCandidateCurrent;
692 return IteratorResult.NeedInputNode;
694 case IteratorState.HaveCandidateCurrent:
695 // If there are no more input nodes,
697 // Then candidate node has been selected, and there are no further input nodes
698 this.state = IteratorState.HaveCurrentNoNext;
701 // If the input node is in the same document as the current node,
702 if (this.navCurrent.ComparePosition(input) != XmlNodeOrder.Unknown) {
703 // Then update the current node and get the next input node
704 this.navCurrent = XmlQueryRuntime.SyncToNavigator(this.navCurrent, input);
705 return IteratorResult.NeedInputNode;
708 // Save the input node as navNext
709 this.navNext = XmlQueryRuntime.SyncToNavigator(this.navNext, input);
710 this.state = IteratorState.HaveCurrentHaveNext;
716 if (!this.navStack.IsEmpty) {
718 // Move to the next matching node that is before the top node on the stack in document order
719 if (this.filter.MoveToFollowing(this.navCurrent, this.navStack.Peek()))
721 return IteratorResult.HaveCurrentNode;
723 // Do not include ancestor nodes as part of the preceding axis
724 this.navCurrent.MoveTo(this.navStack.Pop());
726 // No more preceding matches possible
727 if (this.navStack.IsEmpty)
732 if (this.state == IteratorState.HaveCurrentNoNext) {
733 // No more nodes, so iteration is complete
734 this.state = IteratorState.NeedCandidateCurrent;
735 return IteratorResult.NoMoreNodes;
738 // Make next node the current node and start trying to find input node greatest in docorder
739 this.navCurrent = XmlQueryRuntime.SyncToNavigator(this.navCurrent, this.navNext);
740 this.state = IteratorState.HaveCandidateCurrent;
741 return IteratorResult.HaveCurrentNode;
745 /// Return the current result navigator. This is only defined after MoveNext() has returned true or
746 /// IteratorResult.HaveCurrentNode.
748 public XPathNavigator Current {
749 get { return this.navCurrent; }
753 /// Push all ancestors of this.navCurrent onto a stack. The set of preceding nodes should not contain any of these
756 private void PushAncestors() {
757 Debug.Assert(this.state == IteratorState.HaveCurrentHaveNext || this.state == IteratorState.HaveCurrentNoNext);
759 this.navStack.Reset();
761 this.navStack.Push(this.navCurrent.Clone());
763 while (this.navCurrent.MoveToParent());
765 // Pop the root of the tree, since MoveToFollowing calls will never return it
772 /// Iterate over these nodes in document order (filtering out those that do not match the filter test):
774 /// 2. All content-typed nodes which follow the starting node until the ending node is reached
777 /// If the starting node is the same node as the ending node, iterate over the singleton node.
778 /// If the starting node is after the ending node, or is in a different document, iterate to the
779 /// end of the document.
781 [EditorBrowsable(EditorBrowsableState.Never)]
782 public struct NodeRangeIterator {
783 private XmlNavigatorFilter filter;
784 private XPathNavigator navCurrent, navEnd;
785 private IteratorState state;
787 private enum IteratorState {
795 /// Initialize the NodeRangeIterator (no possibility of duplicates).
797 public void Create(XPathNavigator start, XmlNavigatorFilter filter, XPathNavigator end) {
798 // Save start node as current node and save ending node
799 this.navCurrent = XmlQueryRuntime.SyncToNavigator(this.navCurrent, start);
800 this.navEnd = XmlQueryRuntime.SyncToNavigator(this.navEnd, end);
801 this.filter = filter;
803 if (start.IsSamePosition(end)) {
804 // Start is end, so only return node if it is not filtered
805 this.state = !filter.IsFiltered(start) ? IteratorState.HaveCurrentNoNext : IteratorState.NoNext;
808 // Return nodes until end is reached
809 this.state = !filter.IsFiltered(start) ? IteratorState.HaveCurrent : IteratorState.NeedCurrent;
814 /// Position this iterator to the next following node. Return false if there are no more following nodes,
815 /// or if the end node has been reached. Return true if the Current property is set to the next node in
818 public bool MoveNext() {
819 switch (this.state) {
820 case IteratorState.HaveCurrent:
821 this.state = IteratorState.NeedCurrent;
824 case IteratorState.NeedCurrent:
825 // Move to next following node which matches
826 if (!this.filter.MoveToFollowing(this.navCurrent, this.navEnd)) {
827 // No more nodes unless ending node matches
828 if (filter.IsFiltered(this.navEnd)) {
829 this.state = IteratorState.NoNext;
833 this.navCurrent.MoveTo(this.navEnd);
834 this.state = IteratorState.NoNext;
838 case IteratorState.HaveCurrentNoNext:
839 this.state = IteratorState.NoNext;
843 Debug.Assert(this.state == IteratorState.NoNext, "Illegal state: " + this.state);
848 /// Return the current result navigator. This is only defined after MoveNext() has returned true.
850 public XPathNavigator Current {
851 get { return this.navCurrent; }