**** Merged from MCS ****
[mono-project.git] / mcs / class / System.XML / System.Xml.Query / XPathSequence.cs
blobd6f06410050e03e666de16bbef9f9a3a9867bed3
1 //
2 // XPathSequence.cs - represents XPath sequence iterator
3 //
4 // Author:
5 // Atsushi Enomoto <atsushi@ximian.com>
6 //
7 //
8 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 #if NET_2_0
31 using System;
32 using System.Collections;
33 using System.Globalization;
34 using System.Xml;
35 using System.Xml.Schema;
36 using System.Xml.Query;
37 using System.Xml.XPath;
39 namespace Mono.Xml.XPath2
41 public abstract class XPathSequence : IEnumerable, ICloneable
43 XQueryContext ctx;
44 int countCache = -1;
45 int position = 0;
47 internal XPathSequence (XQueryContext ctx)
49 this.ctx = ctx;
52 internal XPathSequence (XPathSequence original)
54 ctx = original.ctx;
55 position = original.position;
58 internal XQueryContext Context {
59 // get { return ctx; }
60 get { return ctx.ContextManager.CurrentContext; }
63 public virtual int Count {
64 get {
65 if (countCache >= 0)
66 return countCache;
67 XPathSequence clone = Clone ();
68 while (clone.MoveNext ())
70 countCache = clone.Position;
71 return countCache;
75 public XPathItem Current {
76 get {
77 if (Position == 0)
78 throw new InvalidOperationException ("XQuery internal error (should not happen)");
79 return CurrentCore;
83 public abstract XPathItem CurrentCore { get; }
85 // Returns 0 if not started, otherwise returns XPath positional integer.
86 public virtual int Position {
87 get { return position; }
90 public virtual bool MoveNext ()
92 if (!MoveNextCore ())
93 return false;
94 position++;
95 return true;
98 protected abstract bool MoveNextCore ();
100 public abstract XPathSequence Clone ();
102 object ICloneable.Clone ()
104 return this.Clone ();
107 public virtual IEnumerator GetEnumerator ()
109 while (MoveNext ())
110 yield return CurrentCore;
115 // empty iterator (still required since it contains XQueryContext)
116 class XPathEmptySequence : XPathSequence
118 internal XPathEmptySequence (XQueryContext ctx)
119 : base (ctx)
123 public override int Count {
124 get { return 0; }
127 protected override bool MoveNextCore ()
129 return false;
132 public override XPathItem CurrentCore {
133 get { throw new InvalidOperationException ("Should not happen. In XPathEmptySequence.Current."); }
136 // Don't return clone. It's waste of resource.
137 public override XPathSequence Clone ()
139 return this;
143 // single item iterator
145 internal class SingleItemIterator : XPathSequence
147 XPathItem item;
148 XPathItem current;
150 // for XQuery execution start point
151 internal SingleItemIterator (XPathItem item, XQueryContext ctx)
152 : base (ctx)
154 this.item = item;
157 private SingleItemIterator (SingleItemIterator other)
158 : base (other)
160 this.item = other.item;
161 this.current = other.current;
164 public override XPathSequence Clone ()
166 return new SingleItemIterator (this);
169 protected override bool MoveNextCore ()
171 if (current == null) {
172 current = item;
173 return true;
175 return false;
178 public override XPathItem CurrentCore {
179 get {
180 return current;
185 // RangeExpr iterator
187 internal class IntegerRangeIterator : XPathSequence
189 static XmlSchemaSimpleType intType = XmlSchemaType.GetBuiltInSimpleType (new XmlQualifiedName ("int", XmlSchema.Namespace));
191 int start;
192 int end;
193 int next;
194 XPathItem current;
196 public IntegerRangeIterator (XQueryContext ctx, int start, int end)
197 : base (ctx)
199 this.start = start;
200 this.end = end;
203 private IntegerRangeIterator (IntegerRangeIterator other)
204 : base (other)
206 this.start = other.start;
207 this.end = other.end;
208 this.next = other.next;
209 this.current = other.current;
212 public override XPathSequence Clone ()
214 return new IntegerRangeIterator (this);
217 protected override bool MoveNextCore ()
219 if (current == null)
220 next = start;
221 if (next > end)
222 return false;
223 current = new XPathAtomicValue (next++, intType);
224 return true;
227 public override XPathItem CurrentCore {
228 get {
229 return current;
234 // Slash iterator
235 // <copy original='System.Xml.XPath/Iterator.cs,
236 // System.Xml.XPath/XPathComparer.cs'>
237 internal class PathStepIterator : XPathSequence
239 XPathSequence left;
240 XPathSequence right;
241 PathStepExpr step;
242 ArrayList nodeStore;
243 SortedList storedIterators;
244 bool finished;
245 XPathSequence nextRight;
247 public PathStepIterator (XPathSequence iter, PathStepExpr source)
248 : base (iter.Context)
250 left = iter;
251 step = source;
254 private PathStepIterator (PathStepIterator other)
255 : base (other)
257 left = other.left.Clone ();
258 step = other.step;
259 if (other.right != null)
260 right = other.right.Clone ();
261 if (other.nodeStore != null)
262 nodeStore = (ArrayList) other.nodeStore.Clone ();
263 if (other.storedIterators != null)
264 storedIterators = (SortedList) other.storedIterators.Clone ();
265 if (other.nextRight != null)
266 nextRight = other.nextRight.Clone ();
269 public override XPathSequence Clone ()
271 return new PathStepIterator (this);
274 protected override bool MoveNextCore ()
276 if (finished)
277 return false;
278 if (step.RequireSorting) {
279 // Mainly '//' ('/descendant-or-self::node()/')
280 if (nodeStore == null) {
281 CollectResults ();
282 if (nodeStore.Count == 0) {
283 finished = true;
284 return false;
285 } else
286 // Initially it must not go to
287 // the while loop below
288 // (.Position -1 is -1).
289 return true;
291 if (nodeStore.Count == Position) {
292 finished = true;
293 return false;
295 while (nodeStore.Count > Position) {
296 if (((XPathNavigator) nodeStore [Position]).ComparePosition (
297 (XPathNavigator) nodeStore [Position - 1]) == XmlNodeOrder.Same)
298 nodeStore.RemoveAt (Position);
299 else
300 break;
303 return true;
304 } else { // Sorting not required
305 if (right == null) { // First time
306 if (!left.MoveNext ())
307 return false;
308 right = step.Next.Evaluate (left);
309 storedIterators = new SortedList (XPathSequenceComparer.Instance);
312 while (true) {
313 while (!right.MoveNext ()) {
314 if (storedIterators.Count > 0) {
315 int last = storedIterators.Count - 1;
316 XPathSequence tmpIter = (XPathSequence) storedIterators.GetByIndex (last);
317 storedIterators.RemoveAt (last);
318 switch (((XPathNavigator) tmpIter.Current).ComparePosition ((XPathNavigator) right.Current)) {
319 case XmlNodeOrder.Same:
320 case XmlNodeOrder.Before:
321 right = tmpIter;
322 continue;
323 default:
324 right = tmpIter;
325 break;
327 break;
328 } else if (nextRight != null) {
329 right = nextRight;
330 nextRight = null;
331 break;
332 } else if (!left.MoveNext ()) {
333 finished = true;
334 return false;
336 else
337 right = step.Next.Evaluate (left);
339 bool loop = true;
340 while (loop) {
341 loop = false;
342 if (nextRight == null) {
343 bool noMoreNext = false;
344 while (nextRight == null || !nextRight.MoveNext ()) {
345 if(left.MoveNext ())
346 nextRight = step.Next.Evaluate (left);
347 else {
348 noMoreNext = true;
349 break;
352 if (noMoreNext)
353 nextRight = null; // FIXME: More efficient code. Maybe making noMoreNext class scope would be better.
355 if (nextRight != null) {
356 switch (((XPathNavigator) right.Current).ComparePosition ((XPathNavigator) nextRight.Current)) {
357 case XmlNodeOrder.After:
358 storedIterators.Add (storedIterators.Count, right);
359 right = nextRight;
360 nextRight = null;
361 loop = true;
362 break;
363 case XmlNodeOrder.Same:
364 if (!nextRight.MoveNext ())
365 nextRight = null;
367 else {
368 int last = storedIterators.Count;
369 if (last > 0) {
370 storedIterators.Add (last, nextRight);
371 nextRight = (XPathSequence) storedIterators.GetByIndex (last);
372 storedIterators.RemoveAt (last);
376 loop = true;
377 break;
381 return true;
386 private void CollectResults ()
388 if (nodeStore != null)
389 return;
390 nodeStore = new ArrayList ();
391 while (true) {
392 while (right == null || !right.MoveNext ()) {
393 if (!left.MoveNext ()) {
394 nodeStore.Sort (XPathNavigatorComparer2.Instance);
395 return;
397 right = step.Next.Evaluate (left);
399 XPathNavigator nav = (XPathNavigator) right.Current;
400 nodeStore.Add (nav);
404 public override XPathItem CurrentCore {
405 get {
406 if (Position <= 0) return null;
407 if (step.RequireSorting) {
408 return (XPathNavigator) nodeStore [Position - 1];
409 } else {
410 return right.Current;
415 public override int Count {
416 get {
417 if (nodeStore == null)
418 return base.Count;
419 else
420 return nodeStore.Count;
425 internal class XPathSequenceComparer : IComparer
427 public static XPathSequenceComparer Instance = new XPathSequenceComparer ();
428 private XPathSequenceComparer ()
432 public int Compare (object o1, object o2)
434 XPathSequence nav1 = o1 as XPathSequence;
435 XPathSequence nav2 = o2 as XPathSequence;
436 if (nav1 == null)
437 return -1;
438 if (nav2 == null)
439 return 1;
440 switch (((XPathNavigator) nav1.Current).ComparePosition ((XPathNavigator) nav2.Current)) {
441 case XmlNodeOrder.Same:
442 return 0;
443 case XmlNodeOrder.After:
444 return -1;
445 default:
446 return 1;
451 internal class XPathNavigatorComparer2 : IComparer
453 public static XPathNavigatorComparer2 Instance = new XPathNavigatorComparer2 ();
454 private XPathNavigatorComparer2 ()
458 public int Compare (object o1, object o2)
460 XPathNavigator nav1 = o1 as XPathNavigator;
461 XPathNavigator nav2 = o2 as XPathNavigator;
462 if (nav1 == null)
463 return -1;
464 if (nav2 == null)
465 return 1;
466 switch (nav1.ComparePosition (nav2)) {
467 case XmlNodeOrder.Same:
468 return 0;
469 case XmlNodeOrder.After:
470 return 1;
471 default:
472 return -1;
477 // </copy>
479 // Filter step iterator
480 internal class FilteredIterator : XPathSequence
482 XPathSequence left;
483 ExprSequence filter;
485 public FilteredIterator (XPathSequence iter, FilterStepExpr source)
486 : base (iter.Context)
488 left = source.Expr.Evaluate (iter);
489 filter = source.Predicate;
492 private FilteredIterator (FilteredIterator other)
493 : base (other)
495 left = other.left.Clone ();
496 filter = other.filter;
499 public override XPathSequence Clone ()
501 return new FilteredIterator (this);
504 protected override bool MoveNextCore ()
506 // FIXME: as for numeric predicates, it is MUCH faster
507 // when it skips apparent non-candidates, with possible
508 // method implementation "XPathSequence.SkipTo (int)".
509 // When it comes true, iteration won't be done first.
510 while (left.MoveNext ()) {
511 bool doesntPass = true;
512 // Treat as OK if any of filter expr passed.
513 // FIXME: handle numeric predicate.
514 foreach (ExprSingle single in filter) {
515 XPathAtomicValue av = single.EvaluateAsAtomic (left);
516 if (av == null)
517 continue;
518 if (SequenceType.IsNumeric (av.XmlType.TypeCode)) {
519 // numeric filter
520 if (av.ValueAsInt32 == left.Position) {
521 doesntPass = false;
522 break;
525 else if (single.EvaluateAsBoolean (left)) {
526 doesntPass = false;
527 break;
530 if (doesntPass)
531 continue;
532 return true;
534 return false;
537 public override XPathItem CurrentCore {
538 get { return left.Current; }
542 // AxisIterator
543 internal class AxisIterator : XPathSequence
545 NodeIterator iter;
546 AxisStepExpr source;
548 public AxisIterator (NodeIterator iter, AxisStepExpr source)
549 : base (iter.Context)
551 this.iter = iter;
552 this.source = source;
555 private AxisIterator (AxisIterator other)
556 : base (other)
558 iter = (NodeIterator) other.iter.Clone ();
559 source = other.source;
562 public override XPathSequence Clone ()
564 return new AxisIterator (this);
567 protected override bool MoveNextCore ()
569 while (iter.MoveNext ()) {
570 if (source.Matches (iter.Current as XPathNavigator))
571 return true;
573 return false;
576 public override XPathItem CurrentCore {
577 get { return iter.Current; }
581 internal abstract class NodeIterator : XPathSequence
583 XPathNavigator node;
584 XPathNavigator current;
585 bool emptyInput;
587 public NodeIterator (XPathNavigator nav, XQueryContext ctx)
588 : base (ctx)
590 this.node = nav.Clone ();
593 internal NodeIterator (NodeIterator other, bool cloneFlag)
594 : base (other)
596 if (other.emptyInput)
597 emptyInput = true;
598 else
599 node = other.node.Clone ();
602 internal XPathNavigator Node {
603 get { return node; }
606 public override bool MoveNext ()
608 if (emptyInput)
609 return false;
610 if (!base.MoveNext ())
611 return false;
612 current = null;
613 return true;
616 public override XPathItem CurrentCore {
617 get {
618 if (current == null)
619 current = node.Clone ();
620 return current;
624 public virtual bool ReverseAxis {
625 get { return false; }
629 // <copy original='System.Xml.XPath/Iterator.cs'>
631 internal class SelfIterator : NodeIterator
633 public SelfIterator (XPathNavigator nav, XQueryContext ctx)
634 : base (nav, ctx)
638 private SelfIterator (SelfIterator other, bool cloneFlag)
639 : base (other, true)
643 public override XPathSequence Clone ()
645 return new SelfIterator (this, true);
648 protected override bool MoveNextCore ()
650 if (Position == 0)
651 return true;
652 return false;
656 internal class ParentIterator : NodeIterator
658 public ParentIterator (XPathNavigator nav, XQueryContext ctx)
659 : base (nav, ctx)
663 private ParentIterator (ParentIterator other, bool cloneFlag)
664 : base (other, true)
668 public override XPathSequence Clone ()
670 return new ParentIterator (this, true);
673 protected override bool MoveNextCore ()
675 if (Position == 0 && Node.MoveToParent ())
676 return true;
677 return false;
680 public override bool ReverseAxis {
681 get { return true; }
685 internal class ChildIterator : NodeIterator
687 public ChildIterator (XPathNavigator nav, XQueryContext ctx)
688 : base (nav, ctx)
692 private ChildIterator (ChildIterator other, bool cloneFlag)
693 : base (other, true)
697 public override XPathSequence Clone ()
699 return new ChildIterator (this, true);
702 protected override bool MoveNextCore ()
704 if (Position == 0)
705 return Node.MoveToFirstChild ();
706 else
707 return Node.MoveToNext ();
711 internal class FollowingSiblingIterator : NodeIterator
713 public FollowingSiblingIterator (XPathNavigator nav, XQueryContext ctx)
714 : base (nav, ctx)
718 private FollowingSiblingIterator (FollowingSiblingIterator other, bool cloneFlag)
719 : base (other, true)
723 public override XPathSequence Clone ()
725 return new FollowingSiblingIterator (this, true);
728 protected override bool MoveNextCore ()
730 return Node.MoveToNext ();
734 internal class PrecedingSiblingIterator : NodeIterator
736 bool finished;
737 bool started;
738 XPathNavigator startPosition;
740 public PrecedingSiblingIterator (XPathNavigator nav, XQueryContext ctx)
741 : base (nav, ctx)
743 startPosition = Node.Clone ();
746 private PrecedingSiblingIterator (PrecedingSiblingIterator other, bool cloneFlag)
747 : base (other, true)
749 startPosition = other.startPosition;
750 started = other.started;
751 finished = other.finished;
754 public override XPathSequence Clone ()
756 return new PrecedingSiblingIterator (this, true);
759 protected override bool MoveNextCore ()
761 if (finished)
762 return false;
763 if (!started) {
764 started = true;
765 Node.MoveToFirst ();
766 } else {
767 Node.MoveToNext ();
769 if (Node.ComparePosition (startPosition) == XmlNodeOrder.Same) {
770 finished = true;
771 return false;
773 else
774 return true;
777 public override bool ReverseAxis {
778 get { return true; }
782 internal class AncestorIterator : NodeIterator
784 bool finished;
785 ArrayList nodes = new ArrayList ();
787 public AncestorIterator (XPathNavigator nav, XQueryContext ctx)
788 : base (nav, ctx)
792 private AncestorIterator (AncestorIterator other, bool cloneFlag)
793 : base (other, true)
795 finished = other.finished;
796 nodes = other.nodes;
799 public override XPathSequence Clone ()
801 return new AncestorIterator (this, true);
804 protected override bool MoveNextCore ()
806 if (finished)
807 return false;
808 if (nodes != null) {
809 nodes = new ArrayList ();
810 while (Node.MoveToParent () && Node.NodeType != XPathNodeType.Root)
811 nodes.Add (Node.Clone ());
812 nodes.Reverse ();
814 if (nodes.Count >= Position)
815 return false;
816 Node.MoveTo (nodes [Position] as XPathNavigator);
817 return true;
820 public override bool ReverseAxis {
821 get { return true; }
824 public override int Count {
825 get {
826 if (Position == 0)
827 return base.Count;
828 return nodes.Count;
833 internal class AncestorOrSelfIterator : NodeIterator
835 bool finished;
836 ArrayList nodes = new ArrayList ();
838 public AncestorOrSelfIterator (XPathNavigator nav, XQueryContext ctx)
839 : base (nav, ctx)
843 private AncestorOrSelfIterator (AncestorOrSelfIterator other, bool cloneFlag)
844 : base (other, true)
846 finished = other.finished;
847 nodes = other.nodes;
850 public override XPathSequence Clone ()
852 return new AncestorOrSelfIterator (this, true);
855 protected override bool MoveNextCore ()
857 if (finished)
858 return false;
859 if (nodes != null) {
860 nodes = new ArrayList ();
861 do {
862 nodes.Add (Node.Clone ());
863 } while (Node.MoveToParent () && Node.NodeType != XPathNodeType.Root);
864 nodes.Reverse ();
866 if (nodes.Count >= Position)
867 return false;
868 Node.MoveTo (nodes [Position] as XPathNavigator);
869 return true;
872 public override bool ReverseAxis {
873 get { return true; }
876 public override int Count {
877 get {
878 if (Position == 0)
879 return base.Count;
880 return nodes.Count;
885 internal class DescendantIterator : NodeIterator
887 private int depth;
888 private bool finished;
890 public DescendantIterator (XPathNavigator nav, XQueryContext ctx)
891 : base (nav, ctx)
895 private DescendantIterator (DescendantIterator other, bool cloneFlag)
896 : base (other, true)
898 finished = other.finished;
899 depth = other.depth;
902 public override XPathSequence Clone ()
904 return new DescendantIterator (this, true);
907 protected override bool MoveNextCore ()
909 if (finished)
910 return false;
912 if (Node.MoveToFirstChild ()) {
913 depth ++;
914 return true;
916 while (depth != 0) {
917 if (Node.MoveToNext ())
918 return true;
920 if (!Node.MoveToParent ()) // should NEVER fail!
921 throw new XmlQueryException ("There seems some bugs on the XPathNavigator implementation class.");
922 depth --;
924 finished = true;
925 return false;
929 internal class DescendantOrSelfIterator : NodeIterator
931 protected int depth;
932 private bool finished;
934 public DescendantOrSelfIterator (XPathNavigator nav, XQueryContext ctx)
935 : base (nav, ctx)
939 protected DescendantOrSelfIterator (DescendantOrSelfIterator other, bool cloneFlag)
940 : base (other, true)
942 depth = other.depth;
943 finished = other.finished;
946 public override XPathSequence Clone ()
948 return new DescendantOrSelfIterator (this, true);
951 protected override bool MoveNextCore ()
953 if (finished)
954 return false;
956 if (Position == 0)
957 return true; // Self
960 if (Node.MoveToFirstChild ()) {
961 depth ++;
962 return true;
964 while (depth != 0) {
965 if (Node.MoveToNext ())
966 return true;
968 if (!Node.MoveToParent ()) // should NEVER fail!
969 throw new XmlQueryException ("There seems some bugs on the XPathNavigator implementation class.");
970 depth --;
972 finished = true;
973 return false;
977 internal class FollowingIterator : NodeIterator
979 private bool finished;
981 public FollowingIterator (XPathNavigator nav, XQueryContext ctx)
982 : base (nav, ctx)
986 protected FollowingIterator (FollowingIterator other, bool cloneFlag)
987 : base (other, true)
989 finished = other.finished;
992 public override XPathSequence Clone ()
994 return new FollowingIterator (this, true);
997 protected override bool MoveNextCore ()
999 if (finished)
1000 return false;
1001 if (Position == 0) {
1002 // At first, it should not iterate children.
1003 if (Node.MoveToNext ())
1004 return true;
1005 else {
1006 while (Node.MoveToParent ())
1007 if (Node.MoveToNext ())
1008 return true;
1010 } else {
1011 if (Node.MoveToFirstChild ())
1012 return true;
1013 do {
1014 if (Node.MoveToNext ())
1015 return true;
1016 } while (Node.MoveToParent ());
1018 finished = true;
1019 return false;
1023 internal class PrecedingIterator : NodeIterator
1025 bool finished;
1026 bool started;
1027 XPathNavigator startPosition;
1029 public PrecedingIterator (XPathNavigator nav, XQueryContext ctx)
1030 : base (nav, ctx)
1032 startPosition = Node.Clone ();
1035 private PrecedingIterator (PrecedingIterator other, bool cloneFlag)
1036 : base (other, true)
1038 startPosition = other.startPosition;
1039 started = other.started;
1040 finished = other.finished;
1043 public override XPathSequence Clone ()
1045 return new PrecedingIterator (this, true);
1048 protected override bool MoveNextCore ()
1050 if (finished)
1051 return false;
1052 if (!started) {
1053 started = true;
1054 Node.MoveToRoot ();
1056 bool loop = true;
1057 while (loop) {
1058 while (!Node.MoveToFirstChild ()) {
1059 while (!Node.MoveToNext ()) {
1060 if (!Node.MoveToParent ()) { // Should not finish, at least before startPosition.
1061 finished = true;
1062 return false;
1065 break;
1067 if (Node.IsDescendant (startPosition))
1068 continue;
1069 loop = false;
1070 break;
1072 if (Node.ComparePosition (startPosition) != XmlNodeOrder.Before) {
1073 // Note that if _nav contains only 1 node, it won't be Same.
1074 finished = true;
1075 return false;
1077 else
1078 return true;
1081 public override bool ReverseAxis {
1082 get { return true; }
1086 internal class NamespaceIterator : NodeIterator
1088 public NamespaceIterator (XPathNavigator nav, XQueryContext ctx)
1089 : base (nav, ctx)
1093 private NamespaceIterator (NamespaceIterator other, bool cloneFlag)
1094 : base (other, true)
1098 public override XPathSequence Clone ()
1100 return new NamespaceIterator (this, true);
1103 protected override bool MoveNextCore ()
1105 if (Position == 0) {
1106 if (Node.MoveToFirstNamespace ())
1107 return true;
1109 else if (Node.MoveToNextNamespace ())
1110 return true;
1111 return false;
1114 public override bool ReverseAxis { get { return true; } }
1117 internal class AttributeIterator : NodeIterator
1119 public AttributeIterator (XPathNavigator nav, XQueryContext ctx)
1120 : base (nav, ctx)
1124 private AttributeIterator (AttributeIterator other, bool cloneFlag)
1125 : base (other, true)
1129 public override XPathSequence Clone ()
1131 return new AttributeIterator (this, true);
1134 protected override bool MoveNextCore ()
1136 if (Position == 0) {
1137 if (Node.MoveToFirstAttribute ())
1138 return true;
1140 else if (Node.MoveToNextAttribute ())
1141 return true;
1142 return false;
1146 // </copy>
1148 internal class ExprSequenceIterator : XPathSequence
1150 XPathSequence contextSequence;
1151 XPathSequence iter;
1152 ExprSequence expr;
1153 int currentExprIndex;
1155 public ExprSequenceIterator (XPathSequence iter, ExprSequence expr)
1156 : base (iter.Context)
1158 contextSequence = iter;
1159 this.expr = expr;
1162 private ExprSequenceIterator (ExprSequenceIterator other)
1163 : base (other)
1165 if (other.iter != null)
1166 iter = other.iter.Clone ();
1167 expr = other.expr;
1168 contextSequence = other.contextSequence;
1169 currentExprIndex = other.currentExprIndex;
1172 public override XPathSequence Clone ()
1174 return new ExprSequenceIterator (this);
1177 protected override bool MoveNextCore ()
1179 if (iter != null && iter.MoveNext ())
1180 return true;
1181 while (currentExprIndex < expr.Count) {
1182 iter = expr [currentExprIndex++].Evaluate (contextSequence);
1183 if (iter.MoveNext ())
1184 return true;
1186 return false;
1189 public override XPathItem CurrentCore {
1190 get { return iter.Current; }
1194 // FLWOR - Order By
1195 internal class FLWORIterator : XPathSequence
1197 XPathSequence contextSequence;
1198 FLWORExpr expr;
1199 ArrayList forStack = new ArrayList ();
1200 IEnumerator en;
1201 bool finished;
1203 public FLWORIterator (XPathSequence iter, FLWORExpr expr)
1204 : base (iter.Context)
1206 this.contextSequence = iter;
1207 this.expr = expr;
1210 private FLWORIterator (FLWORIterator other)
1211 : base (other)
1213 contextSequence = other.contextSequence;
1214 expr = other.expr;
1215 forStack = other.forStack.Clone () as ArrayList;
1216 if (en != null)
1217 en = ((ICloneable) other.en).Clone () as IEnumerator;
1218 finished = other.finished;
1221 public override XPathSequence Clone ()
1223 return new FLWORIterator (this);
1226 protected override bool MoveNextCore ()
1228 if (en == null)
1229 en = GetEnumerator ();
1230 return en.MoveNext ();
1233 public override IEnumerator GetEnumerator ()
1235 return EvaluateRemainingForLet (0);
1238 private IEnumerator EvaluateRemainingForLet (int flcPosition)
1240 // Prepare iteration stack
1241 if (flcPosition < expr.ForLetClauses.Count) {
1242 IEnumerator items = EvaluateRemainingSingleItem (flcPosition, 0);
1243 while (items.MoveNext ())
1244 yield return items.Current;
1245 } else {
1246 bool passedFilter = expr.WhereClause == null;
1247 if (!passedFilter)
1248 passedFilter = expr.WhereClause.EvaluateAsBoolean (contextSequence);
1249 if (passedFilter) {
1250 IEnumerator ie = expr.ReturnExpr.Evaluate (contextSequence).GetEnumerator ();
1251 while (ie.MoveNext ())
1252 yield return (XPathItem) ie.Current;
1257 private IEnumerator EvaluateRemainingSingleItem (int flcPosition, int singlePosition)
1259 if (singlePosition < expr.ForLetClauses [flcPosition].Count) {
1260 ForLetSingleBody sb = expr.ForLetClauses [flcPosition] [singlePosition];
1261 ForSingleBody fsb = sb as ForSingleBody;
1262 if (fsb != null) {
1263 XPathSequence backup = contextSequence;
1264 contextSequence = fsb.Expression.Evaluate (Context.CurrentSequence);
1265 Context.ContextManager.PushCurrentSequence (contextSequence);
1266 while (contextSequence.MoveNext ()) {
1267 XPathItem forItem = (XPathItem) contextSequence.Current;
1268 Context.PushVariable (fsb.PositionalVar, contextSequence.Position);
1269 Context.PushVariable (sb.VarName, forItem);
1270 // recurse here (including following bindings)
1271 IEnumerator items = EvaluateRemainingSingleItem (flcPosition, singlePosition + 1);
1272 while (items.MoveNext ())
1273 yield return (XPathItem) items.Current;
1274 Context.PopVariable ();
1275 Context.PopVariable ();
1277 Context.ContextManager.PopCurrentSequence ();
1278 contextSequence = backup;
1279 } else {
1280 Context.PushVariable (sb.VarName, sb.Expression.Evaluate (contextSequence));
1281 // recurse here (including following bindings)
1282 IEnumerator items = EvaluateRemainingSingleItem (flcPosition, singlePosition + 1);
1283 while (items.MoveNext ())
1284 yield return (XPathItem) items.Current;
1285 Context.PopVariable ();
1287 } else {
1288 // evaluate next binding
1289 IEnumerator items = EvaluateRemainingForLet (flcPosition + 1);
1290 while (items.MoveNext ())
1291 yield return (XPathItem) items.Current;
1295 public override XPathItem CurrentCore {
1296 get { return (XPathItem) en.Current; }
1300 internal class GroupIterator : XPathSequence
1302 GroupExpr expr;
1303 XPathSequence lseq;
1304 XPathSequence rseq;
1305 bool started;
1306 bool left;
1307 bool leftFinished;
1308 bool rightFinished;
1310 public GroupIterator (XPathSequence iter, GroupExpr expr)
1311 : base (iter.Context)
1313 this.expr = expr;
1314 left = true;
1315 lseq = expr.Left.EvaluateOrdered (iter);
1316 rseq = expr.Right.EvaluateOrdered (iter);
1319 private GroupIterator (GroupIterator other)
1320 : base (other)
1322 this.expr = other.expr;
1323 this.started = other.started;
1324 this.left = other.left;
1325 this.leftFinished = other.leftFinished;
1326 this.rightFinished = other.rightFinished;
1327 this.lseq = other.lseq.Clone ();
1328 this.rseq = other.rseq.Clone ();
1331 public override XPathSequence Clone ()
1333 return new GroupIterator (this);
1336 protected override bool MoveNextCore ()
1338 if (leftFinished && rightFinished)
1339 return false;
1340 bool proceeded = false;
1341 if (started) {
1342 if (left) {
1343 if (!leftFinished && lseq.MoveNext ())
1344 proceeded = true;
1345 else
1346 leftFinished = true;
1347 } else {
1348 if (rightFinished && rseq.MoveNext ())
1349 proceeded = true;
1350 else
1351 rightFinished = true;
1353 } else {
1354 started = true;
1355 if (!lseq.MoveNext ()) {
1356 leftFinished = true;
1357 if (!rseq.MoveNext ()) {
1358 rightFinished = true;
1359 return false;
1361 left = false;
1362 return true;
1364 proceeded = true;
1365 if (!rseq.MoveNext ()) {
1366 rightFinished = true;
1367 return true;
1370 if (!proceeded) {
1371 if (expr.AggregationType == AggregationType.Intersect)
1372 return false;
1373 left = !leftFinished;
1374 return !leftFinished || !rightFinished;
1377 XPathNavigator lnav = lseq.Current as XPathNavigator;
1378 XPathNavigator rnav = rseq.Current as XPathNavigator;
1379 if (lnav == null || rnav == null)
1380 throw new XmlQueryException ("XP0006: Evaluation against union, intersect, except expressions must result in nodes.");
1381 XmlNodeOrder order = lnav.ComparePosition (rnav);
1382 switch (order) {
1383 case XmlNodeOrder.Same:
1384 switch (expr.AggregationType) {
1385 case AggregationType.Union:
1386 left = false;
1387 if (!lseq.MoveNext ())
1388 leftFinished = true;
1389 return true;
1390 case AggregationType.Intersect:
1391 return true;
1392 case AggregationType.Except:
1393 default:
1394 return MoveNext ();
1396 case XmlNodeOrder.Before:
1397 left = true;
1398 if (expr.AggregationType == AggregationType.Intersect)
1399 return MoveNext ();
1400 return true;
1401 default: // After, Unknown
1402 left = false;
1403 if (expr.AggregationType == AggregationType.Intersect)
1404 return MoveNext ();
1405 return true;
1409 public override XPathItem CurrentCore {
1410 get { return left ? lseq.Current : rseq.Current; }
1414 internal class AtomizingIterator : XPathSequence
1416 XPathSequence iter;
1418 public AtomizingIterator (XPathSequence iter)
1419 : base (iter.Context)
1421 this.iter = iter;
1424 private AtomizingIterator (AtomizingIterator other)
1425 : base (other)
1427 iter = other.iter.Clone ();
1430 public override XPathSequence Clone ()
1432 return new AtomizingIterator (this);
1435 protected override bool MoveNextCore ()
1437 return iter.MoveNext ();
1440 public override XPathItem CurrentCore {
1441 get {
1442 XPathNavigator nav = iter.Current as XPathNavigator;
1443 if (nav == null)
1444 return (XPathAtomicValue) iter.Current;
1445 if (nav.SchemaInfo != null)
1446 return new XPathAtomicValue (
1447 nav.TypedValue,
1448 nav.SchemaInfo.SchemaType);
1449 else
1450 return new XPathAtomicValue (nav.Value, null);
1455 internal class ConvertingIterator : XPathSequence
1457 XPathSequence iter;
1458 SequenceType type;
1460 public ConvertingIterator (XPathSequence iter, SequenceType type)
1461 : base (iter.Context)
1463 this.iter = iter;
1464 this.type = type;
1467 private ConvertingIterator (ConvertingIterator other)
1468 : base (other)
1470 iter = other.iter.Clone ();
1471 type = other.type;
1474 public override XPathSequence Clone ()
1476 return new ConvertingIterator (this);
1479 protected override bool MoveNextCore ()
1481 return iter.MoveNext ();
1484 public override XPathItem CurrentCore {
1485 get { return type.Convert (iter.Current); }
1489 internal class TracingIterator : XPathSequence
1491 XPathSequence iter;
1492 string format;
1494 public TracingIterator (XPathSequence iter, string format)
1495 : base (iter.Context)
1497 this.iter = iter;
1498 this.format = format;
1501 private TracingIterator (TracingIterator other)
1502 : base (other)
1504 iter = other.iter.Clone ();
1505 format = other.format;
1508 public override XPathSequence Clone ()
1510 return new TracingIterator (this);
1513 protected override bool MoveNextCore ()
1515 if (!iter.MoveNext ())
1516 return false;
1517 // FIXME: use OnMessageEvent
1518 string output = String.Format (format, iter.Current.TypedValue);
1519 Context.StaticContext.OnMessageEvent (iter.Current, new TraceEventArgs (output));
1520 return true;
1523 public override XPathItem CurrentCore {
1524 get { return iter.Current; }
1527 internal class TraceEventArgs : QueryEventArgs
1529 string message;
1531 internal TraceEventArgs (string message)
1533 this.message = message;
1536 public override string Message {
1537 get { return message; }
1543 internal class ListIterator : XPathSequence
1545 IList list;
1547 public ListIterator (XQueryContext ctx, IList list)
1548 : base (ctx)
1550 if (list is ICloneable)
1551 this.list = list;
1552 else
1553 throw new InvalidOperationException (String.Format ("XQuery internal error: target list is not cloneable. List is {0}.", list != null ? list.GetType ().ToString () : "null argument"));
1556 private ListIterator (ListIterator other)
1557 : base (other)
1559 this.list = (IList) ((ICloneable) other.list).Clone ();
1562 public override XPathSequence Clone ()
1564 return new ListIterator (this);
1567 protected override bool MoveNextCore ()
1569 return (Position < list.Count);
1572 public override XPathItem CurrentCore {
1573 get { return (XPathItem) list [Position - 1]; }
1577 internal class EnumeratorIterator : XPathSequence
1579 IEnumerator list;
1581 public EnumeratorIterator (XQueryContext ctx, IEnumerable en)
1582 : base (ctx)
1584 list = en.GetEnumerator ();
1585 if (list is ICloneable)
1586 this.list = list;
1587 else
1588 throw new InvalidOperationException (String.Format ("XQuery internal error: target list's enumerator is not cloneable. List is {0}.", en != null ? en.GetType ().ToString () : "null argument"));
1591 private EnumeratorIterator (EnumeratorIterator other)
1592 : base (other)
1594 this.list = (IEnumerator) ((ICloneable) other.list).Clone ();
1597 public override XPathSequence Clone ()
1599 return new EnumeratorIterator (this);
1602 protected override bool MoveNextCore ()
1604 return list.MoveNext ();
1607 public override XPathItem CurrentCore {
1608 get { return (XPathItem) list.Current; }
1612 internal abstract class WrapperIterator : XPathSequence
1614 XPathSequence source;
1616 public WrapperIterator (XPathSequence source)
1617 : base (source.Context)
1619 this.source = source;
1622 protected WrapperIterator (WrapperIterator other, bool flag)
1623 : base (other)
1625 source = other.source.Clone ();
1628 public XPathSequence Source {
1629 get { return source; }
1632 public override XPathItem CurrentCore {
1633 get { return source.Current; }
1637 internal class RemovalIterator : WrapperIterator
1639 int position;
1641 public RemovalIterator (XPathSequence source, int position)
1642 : base (source)
1644 this.position = position;
1647 protected RemovalIterator (RemovalIterator other)
1648 : base (other, true)
1650 position = other.position;
1653 public override XPathSequence Clone ()
1655 return new RemovalIterator (this);
1658 protected override bool MoveNextCore ()
1660 if (!Source.MoveNext ())
1661 return false;
1662 else if (Source.Position == position) // skip target
1663 return Source.MoveNext ();
1664 else
1665 return true;
1669 internal class InsertingIterator : WrapperIterator
1671 int position;
1672 XPathSequence inserts;
1673 bool sourceFinished;
1674 bool insertsFinished;
1675 XPathSequence currentSequence;
1677 public InsertingIterator (XPathSequence target, int position, XPathSequence inserts)
1678 : base (target)
1680 this.position = position;
1681 this.inserts = inserts;
1682 currentSequence = target;
1685 protected InsertingIterator (InsertingIterator other)
1686 : base (other)
1688 position = other.position;
1689 inserts = other.inserts.Clone ();
1690 sourceFinished = other.sourceFinished;
1691 insertsFinished = other.insertsFinished;
1692 currentSequence =
1693 other.inserts == other.currentSequence ?
1694 inserts : Source;
1697 public override XPathSequence Clone ()
1699 return new InsertingIterator (this);
1702 protected override bool MoveNextCore ()
1704 if (insertsFinished && sourceFinished)
1705 return false;
1706 if (sourceFinished) { // position >= source.Count
1707 currentSequence = inserts;
1708 if (inserts.MoveNext ())
1709 return true;
1710 insertsFinished = true;
1711 return false;
1713 else if (insertsFinished) { // after insertion
1714 if (Source.MoveNext ())
1715 return true;
1716 sourceFinished = true;
1717 return false;
1719 else if (Position >= position - 1) {
1720 currentSequence = inserts;
1721 if (inserts.MoveNext ())
1722 return true;
1723 currentSequence = Source;
1724 insertsFinished = true;
1726 if (Source.MoveNext ())
1727 return true;
1728 sourceFinished = true;
1729 return MoveNextCore ();
1732 public override XPathItem CurrentCore {
1733 get { return currentSequence.Current; }
1737 internal class DistinctValueIterator : XPathSequence
1739 XPathSequence items;
1740 CultureInfo collation;
1741 Hashtable table = new Hashtable ();
1743 public DistinctValueIterator (XQueryContext ctx, XPathSequence items, CultureInfo collation)
1744 : base (ctx)
1746 this.items = items;
1747 this.collation = collation;
1750 protected DistinctValueIterator (DistinctValueIterator other)
1751 : base (other)
1753 items = other.items.Clone ();
1754 collation = other.collation;
1755 table = (Hashtable) other.table.Clone ();
1758 public override XPathSequence Clone ()
1760 return new DistinctValueIterator (this);
1763 protected override bool MoveNextCore ()
1765 if (!items.MoveNext ())
1766 return false;
1767 // FIXME: use collations
1768 // FIXME: check if it really works (esp. Uri et.al)
1769 if (table.Contains (items.Current.TypedValue))
1770 return MoveNextCore ();
1771 return true;
1774 public override XPathItem CurrentCore {
1775 get { return items.Current; }
1780 #endif