2009-04-22 Sebastien Pouliot <sebastien@ximian.com>
[mono-project.git] / mcs / class / System.XML / System.Xml.XPath / Iterator.cs
blobb1c7f8d147ffd70c3c90b62dc02d4e9d81dbbe05
1 //
2 // System.Xml.XPath.BaseIterator
3 //
4 // Author:
5 // Piers Haken (piersh@friskit.com)
6 // Atsushi Enomoto (atsushi@ximian.com)
7 //
8 // (C) 2002 Piers Haken
9 // (C) 2003 Atsushi Enomoto
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 //
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System;
34 using System.Collections;
35 using System.Xml;
36 using System.Xml.XPath;
37 using System.Xml.Xsl;
39 #if NET_2_0
40 using NSResolver = System.Xml.IXmlNamespaceResolver;
41 #else
42 using NSResolver = System.Xml.XmlNamespaceManager;
43 #endif
45 namespace System.Xml.XPath
47 internal abstract class BaseIterator : XPathNodeIterator
49 NSResolver _nsm;
50 int position;
52 internal BaseIterator (BaseIterator other)
54 _nsm = other._nsm;
55 position = other.position;
57 internal BaseIterator (NSResolver nsm)
59 _nsm = nsm;
62 public NSResolver NamespaceManager
64 get { return _nsm; }
65 set { _nsm = value; }
68 public virtual bool ReverseAxis {
69 get { return false; }
72 public int ComparablePosition {
73 get {
74 if (ReverseAxis) {
75 int diff = Count - CurrentPosition + 1;
76 return diff < 1 ? 1 : diff;
78 else
79 return CurrentPosition;
83 public override int CurrentPosition {
84 get { return position; }
87 internal void SetPosition (int pos)
89 position = pos;
92 public override bool MoveNext ()
94 // FIXME: enable this line once I found the culprit of a breakage in WrapperIterator. And remove it again in the final stage.
95 //if (CurrentPosition == 0 && Current != null) throw new Exception (GetType ().FullName);
96 if (!MoveNextCore ())
97 return false;
98 position++;
99 return true;
102 public abstract bool MoveNextCore ();
104 internal XPathNavigator PeekNext ()
106 XPathNodeIterator i = Clone ();
107 return i.MoveNext () ? i.Current : null;
110 public override string ToString ()
112 if (Current != null)
113 return Current.NodeType.ToString () + "[" + CurrentPosition + "] : " + Current.Name + " = " + Current.Value;
114 else
115 return this.GetType().ToString () + "[" + CurrentPosition + "]";
119 internal class WrapperIterator : BaseIterator
121 XPathNodeIterator iter;
123 public WrapperIterator (XPathNodeIterator iter, NSResolver nsm)
124 : base (nsm)
126 this.iter = iter;
129 private WrapperIterator (WrapperIterator other)
130 : base (other)
132 iter = other.iter.Clone ();
135 public override XPathNodeIterator Clone ()
137 return new WrapperIterator (this);
140 public override bool MoveNextCore ()
142 return iter.MoveNext ();
145 public override XPathNavigator Current {
146 get { return iter.Current; }
150 internal abstract class SimpleIterator : BaseIterator
152 protected readonly XPathNavigator _nav;
153 protected XPathNavigator _current;
154 bool skipfirst;
156 public SimpleIterator (BaseIterator iter) : base (iter.NamespaceManager)
158 if (iter.CurrentPosition == 0) {
159 skipfirst = true;
160 iter.MoveNext ();
162 if (iter.CurrentPosition > 0)
163 _nav = iter.Current.Clone ();
165 protected SimpleIterator (SimpleIterator other, bool clone) : base (other)
167 if (other._nav != null)
168 _nav = clone ? other._nav.Clone () : other._nav;
169 skipfirst = other.skipfirst;
171 public SimpleIterator (XPathNavigator nav, NSResolver nsm) : base (nsm)
173 _nav = nav.Clone ();
176 public override bool MoveNext ()
178 if (skipfirst) {
179 if (_nav == null)
180 return false; // empty
181 skipfirst = false;
182 base.SetPosition (1);
183 return true;
184 } else {
185 return base.MoveNext ();
189 public override XPathNavigator Current {
190 get {
191 if (CurrentPosition == 0)
192 return null;
193 _current = _nav;
194 return _current;
199 internal class SelfIterator : SimpleIterator
201 public SelfIterator (BaseIterator iter) : base (iter) {}
202 public SelfIterator (XPathNavigator nav, NSResolver nsm) : base (nav, nsm) {}
203 protected SelfIterator (SelfIterator other, bool clone) : base (other, true)
207 public override XPathNodeIterator Clone () { return new SelfIterator (this, true); }
208 public override bool MoveNextCore ()
210 if (CurrentPosition == 0)
212 return true;
214 return false;
217 public override XPathNavigator Current {
218 get { return CurrentPosition == 0 ? null : _nav; }
222 internal class NullIterator : SelfIterator
224 public NullIterator (BaseIterator iter) : base (iter) {}
225 public NullIterator (XPathNavigator nav) : this (nav, null) {}
226 public NullIterator (XPathNavigator nav, NSResolver nsm) : base (nav, nsm) {}
227 private NullIterator (NullIterator other) : base (other, true) {}
228 public override XPathNodeIterator Clone () { return new NullIterator (this); }
229 public override bool MoveNextCore ()
231 return false;
234 public override int CurrentPosition {
235 get { return 1; }
238 public override XPathNavigator Current {
239 get { return _nav; }
243 internal class ParensIterator : BaseIterator
245 BaseIterator _iter;
247 public ParensIterator (BaseIterator iter) : base (iter.NamespaceManager)
249 _iter = iter;
251 private ParensIterator (ParensIterator other) : base (other)
253 _iter = (BaseIterator) other._iter.Clone ();
255 public override XPathNodeIterator Clone () { return new ParensIterator (this); }
256 public override bool MoveNextCore ()
258 return _iter.MoveNext ();
261 public override XPathNavigator Current { get { return _iter.Current; }}
263 public override int Count { get { return _iter.Count; } }
266 internal class ParentIterator : SimpleIterator
268 bool canMove;
269 public ParentIterator (BaseIterator iter) : base (iter)
271 canMove = _nav.MoveToParent ();
272 //_current = _nav;
274 private ParentIterator (ParentIterator other, bool dummy) : base (other, true)
276 //_current = _nav;
277 canMove = other.canMove;
279 public ParentIterator (XPathNavigator nav, NSResolver nsm) : base (nav, nsm) {}
280 public override XPathNodeIterator Clone () { return new ParentIterator (this, true); }
281 public override bool MoveNextCore ()
283 if (!canMove)
284 return false;
285 canMove = false;
286 return true;
290 internal class ChildIterator : BaseIterator
292 XPathNavigator _nav;
294 public ChildIterator (BaseIterator iter) : base (iter.NamespaceManager)
296 _nav = iter.CurrentPosition == 0 ? iter.PeekNext () : iter.Current;
297 if (_nav != null && _nav.HasChildren)
298 _nav = _nav.Clone ();
299 else
300 _nav = null;
302 private ChildIterator (ChildIterator other) : base (other)
304 _nav = other._nav == null ? null : other._nav.Clone ();
307 public override XPathNodeIterator Clone () { return new ChildIterator (this); }
309 public override bool MoveNextCore ()
311 if (_nav == null)
312 return false;
314 return (CurrentPosition == 0) ? _nav.MoveToFirstChild () : _nav.MoveToNext ();
317 public override XPathNavigator Current {
318 get {
319 if (CurrentPosition == 0)
320 return null;
321 return _nav;
326 internal class FollowingSiblingIterator : SimpleIterator
328 public FollowingSiblingIterator (BaseIterator iter) : base (iter) {}
329 private FollowingSiblingIterator (FollowingSiblingIterator other) : base (other, true) {}
330 public override XPathNodeIterator Clone () { return new FollowingSiblingIterator (this); }
331 public override bool MoveNextCore ()
333 switch (_nav.NodeType) {
334 case XPathNodeType.Attribute:
335 case XPathNodeType.Namespace:
336 // They have no siblings.
337 return false;
339 if (_nav.MoveToNext ())
341 // Current.MoveTo (_nav);
342 return true;
344 return false;
348 internal class PrecedingSiblingIterator : SimpleIterator
350 bool finished;
351 bool started;
352 XPathNavigator startPosition;
354 public PrecedingSiblingIterator (BaseIterator iter) : base (iter)
356 startPosition = iter.Current.Clone ();
358 private PrecedingSiblingIterator (PrecedingSiblingIterator other) : base (other, true)
360 startPosition = other.startPosition;
361 started = other.started;
362 finished = other.finished;
365 public override XPathNodeIterator Clone () { return new PrecedingSiblingIterator (this); }
366 public override bool MoveNextCore ()
368 if (finished)
369 return false;
370 if (!started) {
371 started = true;
372 switch (_nav.NodeType) {
373 case XPathNodeType.Attribute:
374 case XPathNodeType.Namespace:
375 // They have no siblings.
376 finished = true;
377 return false;
380 _nav.MoveToFirst ();
381 if (!_nav.IsSamePosition (startPosition)) {
382 // Current.MoveTo (_nav);
383 return true;
385 } else {
386 if (!_nav.MoveToNext ()) {
387 finished = true;
388 return false;
391 if (_nav.ComparePosition (startPosition) != XmlNodeOrder.Before) {
392 // Note that if _nav contains only 1 node, it won't be Same.
393 finished = true;
394 return false;
395 } else {
396 // Current.MoveTo (_nav);
397 return true;
400 public override bool ReverseAxis {
401 get { return true; }
405 internal class AncestorIterator : SimpleIterator
407 int currentPosition;
408 ArrayList navigators;
409 XPathNavigator startPosition;
411 public AncestorIterator (BaseIterator iter) : base (iter)
413 startPosition = iter.Current.Clone ();
416 private AncestorIterator (AncestorIterator other)
417 : base (other, true)
419 startPosition = other.startPosition;
420 if (other.navigators != null)
421 navigators = (ArrayList) other.navigators;
422 currentPosition = other.currentPosition;
425 public override XPathNodeIterator Clone ()
427 return new AncestorIterator (this);
430 private void CollectResults ()
432 navigators = new ArrayList ();
434 XPathNavigator ancestors = startPosition.Clone ();
435 while (ancestors.NodeType != XPathNodeType.Root && ancestors.MoveToParent ())
436 navigators.Add (ancestors.Clone ());
437 currentPosition = navigators.Count;
440 public override bool MoveNextCore ()
442 if (navigators == null)
443 CollectResults ();
444 if (currentPosition == 0)
445 return false;
446 _nav.MoveTo ((XPathNavigator) navigators [--currentPosition]);
447 // Current.MoveTo (_nav);
448 return true;
451 public override bool ReverseAxis {
452 get { return true; }
455 public override int Count {
456 get {
457 if (navigators == null)
458 CollectResults ();
459 return navigators.Count;
464 internal class AncestorOrSelfIterator : SimpleIterator
466 int currentPosition;
467 ArrayList navigators;
468 XPathNavigator startPosition;
470 public AncestorOrSelfIterator (BaseIterator iter) : base (iter)
472 startPosition = iter.Current.Clone ();
475 private AncestorOrSelfIterator (AncestorOrSelfIterator other)
476 : base (other, true)
478 startPosition = other.startPosition;
479 if (other.navigators != null)
480 navigators = (ArrayList) other.navigators.Clone ();
481 currentPosition = other.currentPosition;
484 public override XPathNodeIterator Clone ()
486 return new AncestorOrSelfIterator (this);
489 private void CollectResults ()
491 navigators = new ArrayList ();
493 XPathNavigator ancestors = startPosition.Clone ();
494 if (!ancestors.MoveToParent ())
495 return;
496 while (ancestors.NodeType != XPathNodeType.Root) {
497 navigators.Add (ancestors.Clone ());
498 ancestors.MoveToParent ();
500 currentPosition = navigators.Count;
503 public override bool MoveNextCore ()
505 if (navigators == null) {
506 CollectResults ();
507 if (startPosition.NodeType != XPathNodeType.Root) {
508 // First time it returns Root
509 _nav.MoveToRoot ();
510 // Current.MoveTo (_nav);
511 return true;
514 if (currentPosition == -1)
515 return false;
516 if (currentPosition-- == 0) {
517 _nav.MoveTo (startPosition);
518 // Current.MoveTo (_nav);
519 return true; // returns self.
521 _nav.MoveTo ((XPathNavigator) navigators [currentPosition]);
522 // Current.MoveTo (_nav);
523 return true;
526 public override bool ReverseAxis {
527 get { return true; }
530 public override int Count {
531 get {
532 if (navigators == null)
533 CollectResults ();
534 return navigators.Count + 1;
539 internal class DescendantIterator : SimpleIterator
541 private int _depth;
542 private bool _finished;
544 public DescendantIterator (BaseIterator iter) : base (iter) {}
546 private DescendantIterator (DescendantIterator other) : base (other, true)
548 _depth = other._depth;
549 _finished = other._finished;
552 public override XPathNodeIterator Clone () { return new DescendantIterator (this); }
554 public override bool MoveNextCore ()
556 if (_finished)
557 return false;
559 if (_nav.MoveToFirstChild ())
561 _depth ++;
562 // Current.MoveTo (_nav);
563 return true;
565 while (_depth != 0)
567 if (_nav.MoveToNext ())
569 // Current.MoveTo (_nav);
570 return true;
572 if (!_nav.MoveToParent ()) // should NEVER fail!
573 throw new XPathException ("Current node is removed while it should not be, or there are some bugs in the XPathNavigator implementation class: " + _nav.GetType ());
574 _depth --;
576 _finished = true;
577 return false;
581 internal class DescendantOrSelfIterator : SimpleIterator
583 private int _depth;
584 private bool _finished;
586 public DescendantOrSelfIterator (BaseIterator iter) : base (iter) {}
588 private DescendantOrSelfIterator (DescendantOrSelfIterator other) : base (other, true)
590 _depth = other._depth;
593 public override XPathNodeIterator Clone () { return new DescendantOrSelfIterator (this); }
595 public override bool MoveNextCore ()
597 if (_finished)
598 return false;
600 if (CurrentPosition == 0)
602 // self
603 // Current.MoveTo (_nav);
604 return true;
606 if (_nav.MoveToFirstChild ())
608 _depth ++;
609 // Current.MoveTo (_nav);
610 return true;
612 while (_depth != 0)
614 if (_nav.MoveToNext ())
616 // Current.MoveTo (_nav);
617 return true;
619 if (!_nav.MoveToParent ()) // should NEVER fail!
620 throw new XPathException ("Current node is removed while it should not be, or there are some bugs in the XPathNavigator implementation class: " + _nav.GetType ());
621 _depth --;
623 _finished = true;
624 return false;
628 internal class FollowingIterator : SimpleIterator
630 private bool _finished = false;
631 public FollowingIterator (BaseIterator iter) : base (iter) {}
632 private FollowingIterator (FollowingIterator other) : base (other, true) {}
633 public override XPathNodeIterator Clone () { return new FollowingIterator (this); }
634 public override bool MoveNextCore ()
636 if (_finished)
637 return false;
638 bool checkChildren = true;
639 if (CurrentPosition == 0)
641 checkChildren = false;
642 switch (_nav.NodeType) {
643 case XPathNodeType.Attribute:
644 case XPathNodeType.Namespace:
645 _nav.MoveToParent ();
646 checkChildren = true;
647 break;
648 default:
649 if (_nav.MoveToNext ())
651 // Current.MoveTo (_nav);
652 return true;
653 } else {
654 while (_nav.MoveToParent ()) {
655 if (_nav.MoveToNext ()) {
656 // Current.MoveTo (_nav);
657 return true;
661 break;
664 if (checkChildren)
666 if (_nav.MoveToFirstChild ())
668 // Current.MoveTo (_nav);
669 return true;
673 if (_nav.MoveToNext ())
675 // Current.MoveTo (_nav);
676 return true;
679 while (_nav.MoveToParent ());
681 _finished = true;
682 return false;
686 internal class PrecedingIterator : SimpleIterator
688 bool finished;
689 bool started;
690 XPathNavigator startPosition;
692 public PrecedingIterator (BaseIterator iter) : base (iter)
694 startPosition = iter.Current.Clone ();
696 private PrecedingIterator (PrecedingIterator other) : base (other, true)
698 startPosition = other.startPosition;
699 started = other.started;
700 finished = other.finished;
702 public override XPathNodeIterator Clone () { return new PrecedingIterator (this); }
703 public override bool MoveNextCore ()
705 if (finished)
706 return false;
707 if (!started) {
708 started = true;
709 _nav.MoveToRoot ();
711 bool loop = true;
712 while (loop) {
713 while (!_nav.MoveToFirstChild ()) {
714 while (!_nav.MoveToNext ()) {
715 if (!_nav.MoveToParent ()) { // Should not finish, at least before startPosition.
716 finished = true;
717 return false;
720 break;
722 if (_nav.IsDescendant (startPosition))
723 continue;
724 loop = false;
725 break;
727 if (_nav.ComparePosition (startPosition) != XmlNodeOrder.Before) {
728 // Note that if _nav contains only 1 node, it won't be Same.
729 finished = true;
730 return false;
731 } else {
732 // Current.MoveTo (_nav);
733 return true;
736 public override bool ReverseAxis {
737 get { return true; }
741 internal class NamespaceIterator : SimpleIterator
743 public NamespaceIterator (BaseIterator iter) : base (iter) {}
744 private NamespaceIterator (NamespaceIterator other) : base (other, true) {}
745 public override XPathNodeIterator Clone () { return new NamespaceIterator (this); }
746 public override bool MoveNextCore ()
748 if (CurrentPosition == 0)
750 if (_nav.MoveToFirstNamespace ())
752 // Current.MoveTo (_nav);
753 return true;
756 else if (_nav.MoveToNextNamespace ())
758 // Current.MoveTo (_nav);
759 return true;
761 return false;
765 internal class AttributeIterator : SimpleIterator
767 public AttributeIterator (BaseIterator iter) : base (iter) {}
768 private AttributeIterator (AttributeIterator other) : base (other, true) {}
769 public override XPathNodeIterator Clone () { return new AttributeIterator (this); }
770 public override bool MoveNextCore ()
772 if (CurrentPosition == 0)
774 if (_nav.MoveToFirstAttribute ())
776 // Current.MoveTo (_nav);
777 return true;
780 else if (_nav.MoveToNextAttribute ())
782 // Current.MoveTo (_nav);
783 return true;
785 return false;
789 internal class AxisIterator : BaseIterator
791 private BaseIterator _iter;
792 private NodeTest _test;
794 //string name, ns;
795 //XPathNodeType matchType;
797 public AxisIterator (BaseIterator iter, NodeTest test) : base (iter.NamespaceManager)
799 _iter = iter;
800 _test = test;
801 //test.GetInfo (out name, out ns, out matchType, NamespaceManager);
802 // if (name != null)
803 // name = Current.NameTable.Add (name);
805 // if (ns != null)
806 // ns = Current.NameTable.Add (ns);
809 private AxisIterator (AxisIterator other) : base (other)
811 _iter = (BaseIterator) other._iter.Clone ();
812 _test = other._test;
813 //name = other.name;
814 //ns = other.ns;
815 //matchType = other.matchType;
817 public override XPathNodeIterator Clone () { return new AxisIterator (this); }
819 public override bool MoveNextCore ()
821 while (_iter.MoveNext ())
823 if (_test.Match (NamespaceManager, _iter.Current))
825 return true;
828 return false;
830 public override XPathNavigator Current { get { return CurrentPosition == 0 ? null : _iter.Current; }}
832 public override bool ReverseAxis {
833 get { return _iter.ReverseAxis; }
837 internal class SimpleSlashIterator : BaseIterator
839 private NodeSet _expr;
840 private BaseIterator _left, _right;
841 private XPathNavigator _current;
843 public SimpleSlashIterator (BaseIterator left, NodeSet expr)
844 : base (left.NamespaceManager)
846 this._left = left;
847 this._expr = expr;
850 private SimpleSlashIterator (SimpleSlashIterator other)
851 : base (other)
853 _expr = other._expr;
854 _left = (BaseIterator) other._left.Clone ();
855 if (other._right != null)
856 _right = (BaseIterator) other._right.Clone ();
859 public override XPathNodeIterator Clone () { return new SimpleSlashIterator (this); }
861 public override bool MoveNextCore ()
863 while (_right == null || !_right.MoveNext ()) {
864 if (!_left.MoveNext ())
865 return false;
866 _right = _expr.EvaluateNodeSet (_left);
868 if (_current == null)
869 _current = _right.Current.Clone ();
870 else
871 if (! _current.MoveTo (_right.Current) )
872 _current = _right.Current.Clone ();
873 return true;
876 public override XPathNavigator Current {
877 get { return _current; }
881 internal class SortedIterator : BaseIterator
883 ArrayList list;
885 public SortedIterator (BaseIterator iter) : base (iter.NamespaceManager)
887 list = new ArrayList ();
888 while (iter.MoveNext ())
889 list.Add (iter.Current.Clone ());
891 // sort
892 if (list.Count == 0)
893 return;
894 XPathNavigator prev = (XPathNavigator) list [0];
895 list.Sort (XPathNavigatorComparer.Instance);
896 for (int i = 1; i < list.Count; i++) {
897 XPathNavigator n = (XPathNavigator) list [i];
898 if (prev.IsSamePosition (n)) {
899 list.RemoveAt (i);
900 i--;
902 else
903 prev = n;
907 public SortedIterator (SortedIterator other) : base (other)
909 this.list = other.list;
910 SetPosition (other.CurrentPosition);
913 public override XPathNodeIterator Clone () { return new SortedIterator (this); }
915 public override bool MoveNextCore ()
917 return CurrentPosition < list.Count;
920 public override XPathNavigator Current {
921 get { return CurrentPosition == 0 ? null : (XPathNavigator) list [CurrentPosition - 1]; }
924 public override int Count {
925 get { return list.Count; }
929 // NOTE: it is *not* sorted. Do not directly use it without checking sorting requirement.
930 internal class SlashIterator : BaseIterator
932 private BaseIterator _iterLeft;
933 private BaseIterator _iterRight;
934 private NodeSet _expr;
935 SortedList _iterList;
936 bool _finished;
937 BaseIterator _nextIterRight;
939 public SlashIterator (BaseIterator iter, NodeSet expr) : base (iter.NamespaceManager)
941 _iterLeft = iter;
942 _expr = expr;
945 private SlashIterator (SlashIterator other) : base (other)
947 _iterLeft = (BaseIterator) other._iterLeft.Clone ();
948 if (other._iterRight != null)
949 _iterRight = (BaseIterator) other._iterRight.Clone ();
950 _expr = other._expr;
951 if (other._iterList != null)
952 _iterList = (SortedList) other._iterList.Clone ();
953 _finished = other._finished;
954 if (other._nextIterRight != null)
955 _nextIterRight = (BaseIterator) other._nextIterRight.Clone ();
957 public override XPathNodeIterator Clone () { return new SlashIterator (this); }
959 public override bool MoveNextCore ()
961 if (_finished)
962 return false;
964 if (_iterRight == null) { // First time
965 if (!_iterLeft.MoveNext ())
966 return false;
967 _iterRight = _expr.EvaluateNodeSet (_iterLeft);
968 _iterList = new SortedList (XPathIteratorComparer.Instance);
971 while (true) {
972 while (!_iterRight.MoveNext ()) {
973 if (_iterList.Count > 0) {
974 int last = _iterList.Count - 1;
975 _iterRight = (BaseIterator) _iterList.GetByIndex (last);
976 _iterList.RemoveAt (last);
977 break;
978 } else if (_nextIterRight != null) {
979 _iterRight = _nextIterRight;
980 _nextIterRight = null;
981 break;
982 } else if (!_iterLeft.MoveNext ()) {
983 _finished = true;
984 return false;
986 else
987 _iterRight = _expr.EvaluateNodeSet (_iterLeft);
989 bool loop = true;
990 while (loop) {
991 loop = false;
992 if (_nextIterRight == null) {
993 bool noMoreNext = false;
994 while (_nextIterRight == null || !_nextIterRight.MoveNext ()) {
995 if(_iterLeft.MoveNext ())
996 _nextIterRight = _expr.EvaluateNodeSet (_iterLeft);
997 else {
998 noMoreNext = true;
999 break;
1002 if (noMoreNext)
1003 _nextIterRight = null; // FIXME: More efficient code. Maybe making noMoreNext class scope would be better.
1005 if (_nextIterRight != null) {
1006 switch (_iterRight.Current.ComparePosition (_nextIterRight.Current)) {
1007 case XmlNodeOrder.After:
1008 _iterList [_iterRight] = _iterRight;
1009 _iterRight = _nextIterRight;
1010 _nextIterRight = null;
1011 loop = true;
1012 break;
1013 case XmlNodeOrder.Same:
1014 if (!_nextIterRight.MoveNext ())
1015 _nextIterRight = null;
1017 else {
1018 int last = _iterList.Count;
1019 _iterList [_nextIterRight] = _nextIterRight;
1020 if (last != _iterList.Count) {
1021 _nextIterRight = (BaseIterator) _iterList.GetByIndex (last);
1022 _iterList.RemoveAt (last);
1026 loop = true;
1027 break;
1031 return true;
1035 public override XPathNavigator Current {
1036 get {
1037 return (CurrentPosition == 0) ? null : _iterRight.Current;
1042 internal class PredicateIterator : BaseIterator
1044 private BaseIterator _iter;
1045 private Expression _pred;
1046 private XPathResultType resType;
1047 private bool finished;
1049 public PredicateIterator (BaseIterator iter, Expression pred) : base (iter.NamespaceManager)
1051 _iter = iter;
1052 _pred = pred;
1053 resType = pred.GetReturnType (iter);
1056 private PredicateIterator (PredicateIterator other) : base (other)
1058 _iter = (BaseIterator) other._iter.Clone ();
1059 _pred = other._pred;
1060 resType = other.resType;
1061 finished = other.finished;
1063 public override XPathNodeIterator Clone () { return new PredicateIterator (this); }
1065 public override bool MoveNextCore ()
1067 if (finished)
1068 return false;
1069 while (_iter.MoveNext ())
1071 switch (resType) {
1072 case XPathResultType.Number:
1073 if (_pred.EvaluateNumber (_iter) != _iter.ComparablePosition)
1074 continue;
1075 break;
1076 case XPathResultType.Any: {
1077 object result = _pred.Evaluate (_iter);
1078 if (result is double)
1080 if ((double) result != _iter.ComparablePosition)
1081 continue;
1083 else if (!XPathFunctions.ToBoolean (result))
1084 continue;
1086 break;
1087 default:
1088 if (!_pred.EvaluateBoolean (_iter))
1089 continue;
1090 break;
1093 return true;
1095 finished = true;
1096 return false;
1098 public override XPathNavigator Current {
1099 get { return CurrentPosition == 0 ? null : _iter.Current; }}
1100 public override bool ReverseAxis {
1101 get { return _iter.ReverseAxis; }
1103 public override string ToString () { return _iter.GetType ().FullName; }
1106 internal class ListIterator : BaseIterator
1108 private IList _list;
1110 public ListIterator (BaseIterator iter, IList list) : base (iter.NamespaceManager)
1112 _list = list;
1115 public ListIterator (IList list, NSResolver nsm) : base (nsm)
1117 _list = list;
1120 private ListIterator (ListIterator other) : base (other)
1122 _list = other._list;
1124 public override XPathNodeIterator Clone () { return new ListIterator (this); }
1126 public override bool MoveNextCore ()
1128 if (CurrentPosition >= _list.Count)
1129 return false;
1130 return true;
1132 public override XPathNavigator Current {
1133 get {
1134 if (_list.Count == 0 || CurrentPosition == 0)
1135 return null;
1136 return (XPathNavigator) _list [CurrentPosition - 1];
1140 public override int Count { get { return _list.Count; } }
1144 internal class UnionIterator : BaseIterator
1146 private BaseIterator _left, _right;
1147 private bool keepLeft;
1148 private bool keepRight;
1149 XPathNavigator _current;
1151 public UnionIterator (BaseIterator iter, BaseIterator left, BaseIterator right) : base (iter.NamespaceManager)
1153 _left = left;
1154 _right = right;
1157 private UnionIterator (UnionIterator other) : base (other)
1159 _left = (BaseIterator) other._left.Clone ();
1160 _right = (BaseIterator) other._right.Clone ();
1161 keepLeft = other.keepLeft;
1162 keepRight = other.keepRight;
1163 if (other._current != null)
1164 _current = other._current.Clone ();
1166 public override XPathNodeIterator Clone () { return new UnionIterator (this); }
1168 public override bool MoveNextCore ()
1170 if (!keepLeft)
1171 keepLeft = _left.MoveNext ();
1172 if (!keepRight)
1173 keepRight = _right.MoveNext ();
1175 if (!keepLeft && !keepRight)
1176 return false;
1178 if (!keepRight) {
1179 keepLeft = false;
1180 SetCurrent (_left);
1181 return true;
1182 } else if (!keepLeft) {
1183 keepRight = false;
1184 SetCurrent (_right);
1185 return true;
1188 switch (_left.Current.ComparePosition (_right.Current)) {
1189 case XmlNodeOrder.Same:
1190 // consume both. i.e. don't output duplicate result.
1191 keepLeft = keepRight = false;
1192 SetCurrent (_right);
1193 return true;
1194 case XmlNodeOrder.Before:
1195 case XmlNodeOrder.Unknown: // Maybe happen because of "document(a) | document(b)"
1196 keepLeft = false;
1197 SetCurrent (_left);
1198 return true;
1199 case XmlNodeOrder.After:
1200 keepRight = false;
1201 SetCurrent (_right);
1202 return true;
1203 default:
1204 throw new InvalidOperationException ("Should not happen.");
1208 private void SetCurrent (XPathNodeIterator iter)
1210 if (_current == null)
1211 _current = iter.Current.Clone ();
1212 else
1213 if (! _current.MoveTo (iter.Current) )
1214 _current = iter.Current.Clone ();
1217 public override XPathNavigator Current
1219 get { return CurrentPosition > 0 ? _current : null; }
1223 internal class OrderedIterator : BaseIterator
1225 BaseIterator iter;
1226 ArrayList list;
1227 int index = -1;
1229 public OrderedIterator (BaseIterator iter)
1230 : base (iter.NamespaceManager)
1232 // if (iter.Ordered)
1233 // if (false)
1234 // this.iter = iter;
1235 // else
1237 list = new ArrayList ();
1238 while (iter.MoveNext ())
1239 list.Add (iter.Current);
1240 list.Sort (XPathNavigatorComparer.Instance);
1244 private OrderedIterator (OrderedIterator other, bool dummy)
1245 : base (other)
1247 if (other.iter != null)
1248 iter = (BaseIterator) other.iter.Clone ();
1249 list = other.list;
1250 index = other.index;
1253 public override XPathNodeIterator Clone ()
1255 return new OrderedIterator (this);
1258 public override bool MoveNextCore ()
1260 if (iter != null)
1261 return iter.MoveNext ();
1262 else if (index++ < list.Count)
1263 return true;
1264 index--;
1265 return false;
1268 public override XPathNavigator Current {
1269 get { return iter != null ? iter.Current : index < 0 ? null : (XPathNavigator) list [index]; }