2 // XPathSequence.cs - represents XPath sequence iterator
5 // Atsushi Enomoto <atsushi@ximian.com>
8 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
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:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
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.
32 using System
.Collections
;
33 using System
.Globalization
;
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
47 internal XPathSequence (XQueryContext ctx
)
52 internal XPathSequence (XPathSequence original
)
55 position
= original
.position
;
58 internal XQueryContext Context
{
59 // get { return ctx; }
60 get { return ctx.ContextManager.CurrentContext; }
63 public virtual int Count
{
67 XPathSequence clone
= Clone ();
68 while (clone
.MoveNext ())
70 countCache
= clone
.Position
;
75 public XPathItem Current
{
78 throw new InvalidOperationException ("XQuery internal error (should not happen)");
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 ()
98 protected abstract bool MoveNextCore ();
100 public abstract XPathSequence
Clone ();
102 object ICloneable
.Clone ()
104 return this.Clone ();
107 public virtual IEnumerator
GetEnumerator ()
110 yield return CurrentCore
;
115 // empty iterator (still required since it contains XQueryContext)
116 class XPathEmptySequence
: XPathSequence
118 internal XPathEmptySequence (XQueryContext ctx
)
123 public override int Count
{
127 protected override bool MoveNextCore ()
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 ()
143 // single item iterator
145 internal class SingleItemIterator
: XPathSequence
150 // for XQuery execution start point
151 internal SingleItemIterator (XPathItem item
, XQueryContext ctx
)
157 private SingleItemIterator (SingleItemIterator 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) {
178 public override XPathItem CurrentCore
{
185 // RangeExpr iterator
187 internal class IntegerRangeIterator
: XPathSequence
189 static XmlSchemaSimpleType intType
= XmlSchemaType
.GetBuiltInSimpleType (new XmlQualifiedName ("int", XmlSchema
.Namespace
));
196 public IntegerRangeIterator (XQueryContext ctx
, int start
, int end
)
203 private IntegerRangeIterator (IntegerRangeIterator 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 ()
223 current
= new XPathAtomicValue (next
++, intType
);
227 public override XPathItem CurrentCore
{
235 // <copy original='System.Xml.XPath/Iterator.cs,
236 // System.Xml.XPath/XPathComparer.cs'>
237 internal class PathStepIterator
: XPathSequence
243 SortedList storedIterators
;
245 XPathSequence nextRight
;
247 public PathStepIterator (XPathSequence iter
, PathStepExpr source
)
248 : base (iter
.Context
)
254 private PathStepIterator (PathStepIterator other
)
257 left
= other
.left
.Clone ();
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 ()
278 if (step
.RequireSorting
) {
279 // Mainly '//' ('/descendant-or-self::node()/')
280 if (nodeStore
== null) {
282 if (nodeStore
.Count
== 0) {
286 // Initially it must not go to
287 // the while loop below
288 // (.Position -1 is -1).
291 if (nodeStore
.Count
== Position
) {
295 while (nodeStore
.Count
> Position
) {
296 if (((XPathNavigator
) nodeStore
[Position
]).ComparePosition (
297 (XPathNavigator
) nodeStore
[Position
- 1]) == XmlNodeOrder
.Same
)
298 nodeStore
.RemoveAt (Position
);
304 } else { // Sorting not required
305 if (right
== null) { // First time
306 if (!left
.MoveNext ())
308 right
= step
.Next
.Evaluate (left
);
309 storedIterators
= new SortedList (XPathSequenceComparer
.Instance
);
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
:
328 } else if (nextRight
!= null) {
332 } else if (!left
.MoveNext ()) {
337 right
= step
.Next
.Evaluate (left
);
342 if (nextRight
== null) {
343 bool noMoreNext
= false;
344 while (nextRight
== null || !nextRight
.MoveNext ()) {
346 nextRight
= step
.Next
.Evaluate (left
);
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
);
363 case XmlNodeOrder
.Same
:
364 if (!nextRight
.MoveNext ())
368 int last
= storedIterators
.Count
;
370 storedIterators
.Add (last
, nextRight
);
371 nextRight
= (XPathSequence
) storedIterators
.GetByIndex (last
);
372 storedIterators
.RemoveAt (last
);
386 private void CollectResults ()
388 if (nodeStore
!= null)
390 nodeStore
= new ArrayList ();
392 while (right
== null || !right
.MoveNext ()) {
393 if (!left
.MoveNext ()) {
394 nodeStore
.Sort (XPathNavigatorComparer2
.Instance
);
397 right
= step
.Next
.Evaluate (left
);
399 XPathNavigator nav
= (XPathNavigator
) right
.Current
;
404 public override XPathItem CurrentCore
{
406 if (Position
<= 0) return null;
407 if (step
.RequireSorting
) {
408 return (XPathNavigator
) nodeStore
[Position
- 1];
410 return right
.Current
;
415 public override int Count
{
417 if (nodeStore
== null)
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
;
440 switch (((XPathNavigator
) nav1
.Current
).ComparePosition ((XPathNavigator
) nav2
.Current
)) {
441 case XmlNodeOrder
.Same
:
443 case XmlNodeOrder
.After
:
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
;
466 switch (nav1
.ComparePosition (nav2
)) {
467 case XmlNodeOrder
.Same
:
469 case XmlNodeOrder
.After
:
479 // Filter step iterator
480 internal class FilteredIterator
: XPathSequence
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
)
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
);
518 if (SequenceType
.IsNumeric (av
.XmlType
.TypeCode
)) {
520 if (av
.ValueAsInt32
== left
.Position
) {
525 else if (single
.EvaluateAsBoolean (left
)) {
537 public override XPathItem CurrentCore
{
538 get { return left.Current; }
543 internal class AxisIterator
: XPathSequence
548 public AxisIterator (NodeIterator iter
, AxisStepExpr source
)
549 : base (iter
.Context
)
552 this.source
= source
;
555 private AxisIterator (AxisIterator 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
))
576 public override XPathItem CurrentCore
{
577 get { return iter.Current; }
581 internal abstract class NodeIterator
: XPathSequence
584 XPathNavigator current
;
587 public NodeIterator (XPathNavigator nav
, XQueryContext ctx
)
590 this.node
= nav
.Clone ();
593 internal NodeIterator (NodeIterator other
, bool cloneFlag
)
596 if (other
.emptyInput
)
599 node
= other
.node
.Clone ();
602 internal XPathNavigator Node
{
606 public override bool MoveNext ()
610 if (!base.MoveNext ())
616 public override XPathItem CurrentCore
{
619 current
= node
.Clone ();
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
)
638 private SelfIterator (SelfIterator other
, bool cloneFlag
)
643 public override XPathSequence
Clone ()
645 return new SelfIterator (this, true);
648 protected override bool MoveNextCore ()
656 internal class ParentIterator
: NodeIterator
658 public ParentIterator (XPathNavigator nav
, XQueryContext ctx
)
663 private ParentIterator (ParentIterator other
, bool cloneFlag
)
668 public override XPathSequence
Clone ()
670 return new ParentIterator (this, true);
673 protected override bool MoveNextCore ()
675 if (Position
== 0 && Node
.MoveToParent ())
680 public override bool ReverseAxis
{
685 internal class ChildIterator
: NodeIterator
687 public ChildIterator (XPathNavigator nav
, XQueryContext ctx
)
692 private ChildIterator (ChildIterator other
, bool cloneFlag
)
697 public override XPathSequence
Clone ()
699 return new ChildIterator (this, true);
702 protected override bool MoveNextCore ()
705 return Node
.MoveToFirstChild ();
707 return Node
.MoveToNext ();
711 internal class FollowingSiblingIterator
: NodeIterator
713 public FollowingSiblingIterator (XPathNavigator nav
, XQueryContext ctx
)
718 private FollowingSiblingIterator (FollowingSiblingIterator other
, bool cloneFlag
)
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
738 XPathNavigator startPosition
;
740 public PrecedingSiblingIterator (XPathNavigator nav
, XQueryContext ctx
)
743 startPosition
= Node
.Clone ();
746 private PrecedingSiblingIterator (PrecedingSiblingIterator other
, bool cloneFlag
)
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 ()
769 if (Node
.ComparePosition (startPosition
) == XmlNodeOrder
.Same
) {
777 public override bool ReverseAxis
{
782 internal class AncestorIterator
: NodeIterator
785 ArrayList nodes
= new ArrayList ();
787 public AncestorIterator (XPathNavigator nav
, XQueryContext ctx
)
792 private AncestorIterator (AncestorIterator other
, bool cloneFlag
)
795 finished
= other
.finished
;
799 public override XPathSequence
Clone ()
801 return new AncestorIterator (this, true);
804 protected override bool MoveNextCore ()
809 nodes
= new ArrayList ();
810 while (Node
.MoveToParent () && Node
.NodeType
!= XPathNodeType
.Root
)
811 nodes
.Add (Node
.Clone ());
814 if (nodes
.Count
>= Position
)
816 Node
.MoveTo (nodes
[Position
] as XPathNavigator
);
820 public override bool ReverseAxis
{
824 public override int Count
{
833 internal class AncestorOrSelfIterator
: NodeIterator
836 ArrayList nodes
= new ArrayList ();
838 public AncestorOrSelfIterator (XPathNavigator nav
, XQueryContext ctx
)
843 private AncestorOrSelfIterator (AncestorOrSelfIterator other
, bool cloneFlag
)
846 finished
= other
.finished
;
850 public override XPathSequence
Clone ()
852 return new AncestorOrSelfIterator (this, true);
855 protected override bool MoveNextCore ()
860 nodes
= new ArrayList ();
862 nodes
.Add (Node
.Clone ());
863 } while (Node
.MoveToParent () && Node
.NodeType
!= XPathNodeType
.Root
);
866 if (nodes
.Count
>= Position
)
868 Node
.MoveTo (nodes
[Position
] as XPathNavigator
);
872 public override bool ReverseAxis
{
876 public override int Count
{
885 internal class DescendantIterator
: NodeIterator
888 private bool finished
;
890 public DescendantIterator (XPathNavigator nav
, XQueryContext ctx
)
895 private DescendantIterator (DescendantIterator other
, bool cloneFlag
)
898 finished
= other
.finished
;
902 public override XPathSequence
Clone ()
904 return new DescendantIterator (this, true);
907 protected override bool MoveNextCore ()
912 if (Node
.MoveToFirstChild ()) {
917 if (Node
.MoveToNext ())
920 if (!Node
.MoveToParent ()) // should NEVER fail!
921 throw new XmlQueryException ("There seems some bugs on the XPathNavigator implementation class.");
929 internal class DescendantOrSelfIterator
: NodeIterator
932 private bool finished
;
934 public DescendantOrSelfIterator (XPathNavigator nav
, XQueryContext ctx
)
939 protected DescendantOrSelfIterator (DescendantOrSelfIterator other
, bool cloneFlag
)
943 finished
= other
.finished
;
946 public override XPathSequence
Clone ()
948 return new DescendantOrSelfIterator (this, true);
951 protected override bool MoveNextCore ()
960 if (Node
.MoveToFirstChild ()) {
965 if (Node
.MoveToNext ())
968 if (!Node
.MoveToParent ()) // should NEVER fail!
969 throw new XmlQueryException ("There seems some bugs on the XPathNavigator implementation class.");
977 internal class FollowingIterator
: NodeIterator
979 private bool finished
;
981 public FollowingIterator (XPathNavigator nav
, XQueryContext ctx
)
986 protected FollowingIterator (FollowingIterator other
, bool cloneFlag
)
989 finished
= other
.finished
;
992 public override XPathSequence
Clone ()
994 return new FollowingIterator (this, true);
997 protected override bool MoveNextCore ()
1001 if (Position
== 0) {
1002 // At first, it should not iterate children.
1003 if (Node
.MoveToNext ())
1006 while (Node
.MoveToParent ())
1007 if (Node
.MoveToNext ())
1011 if (Node
.MoveToFirstChild ())
1014 if (Node
.MoveToNext ())
1016 } while (Node
.MoveToParent ());
1023 internal class PrecedingIterator
: NodeIterator
1027 XPathNavigator startPosition
;
1029 public PrecedingIterator (XPathNavigator nav
, XQueryContext 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 ()
1058 while (!Node
.MoveToFirstChild ()) {
1059 while (!Node
.MoveToNext ()) {
1060 if (!Node
.MoveToParent ()) { // Should not finish, at least before startPosition.
1067 if (Node
.IsDescendant (startPosition
))
1072 if (Node
.ComparePosition (startPosition
) != XmlNodeOrder
.Before
) {
1073 // Note that if _nav contains only 1 node, it won't be Same.
1081 public override bool ReverseAxis
{
1082 get { return true; }
1086 internal class NamespaceIterator
: NodeIterator
1088 public NamespaceIterator (XPathNavigator nav
, XQueryContext 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 ())
1109 else if (Node
.MoveToNextNamespace ())
1114 public override bool ReverseAxis { get { return true; }
}
1117 internal class AttributeIterator
: NodeIterator
1119 public AttributeIterator (XPathNavigator nav
, XQueryContext 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 ())
1140 else if (Node
.MoveToNextAttribute ())
1148 internal class ExprSequenceIterator
: XPathSequence
1150 XPathSequence contextSequence
;
1153 int currentExprIndex
;
1155 public ExprSequenceIterator (XPathSequence iter
, ExprSequence expr
)
1156 : base (iter
.Context
)
1158 contextSequence
= iter
;
1162 private ExprSequenceIterator (ExprSequenceIterator other
)
1165 if (other
.iter
!= null)
1166 iter
= other
.iter
.Clone ();
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 ())
1181 while (currentExprIndex
< expr
.Count
) {
1182 iter
= expr
[currentExprIndex
++].Evaluate (contextSequence
);
1183 if (iter
.MoveNext ())
1189 public override XPathItem CurrentCore
{
1190 get { return iter.Current; }
1195 internal class FLWORIterator
: XPathSequence
1197 XPathSequence contextSequence
;
1199 ArrayList forStack
= new ArrayList ();
1203 public FLWORIterator (XPathSequence iter
, FLWORExpr expr
)
1204 : base (iter
.Context
)
1206 this.contextSequence
= iter
;
1210 private FLWORIterator (FLWORIterator other
)
1213 contextSequence
= other
.contextSequence
;
1215 forStack
= other
.forStack
.Clone () as ArrayList
;
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 ()
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
;
1246 bool passedFilter
= expr
.WhereClause
== null;
1248 passedFilter
= expr
.WhereClause
.EvaluateAsBoolean (contextSequence
);
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
;
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
;
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 ();
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
1310 public GroupIterator (XPathSequence iter
, GroupExpr expr
)
1311 : base (iter
.Context
)
1315 lseq
= expr
.Left
.EvaluateOrdered (iter
);
1316 rseq
= expr
.Right
.EvaluateOrdered (iter
);
1319 private GroupIterator (GroupIterator 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
)
1340 bool proceeded
= false;
1343 if (!leftFinished
&& lseq
.MoveNext ())
1346 leftFinished
= true;
1348 if (rightFinished
&& rseq
.MoveNext ())
1351 rightFinished
= true;
1355 if (!lseq
.MoveNext ()) {
1356 leftFinished
= true;
1357 if (!rseq
.MoveNext ()) {
1358 rightFinished
= true;
1365 if (!rseq
.MoveNext ()) {
1366 rightFinished
= true;
1371 if (expr
.AggregationType
== AggregationType
.Intersect
)
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
);
1383 case XmlNodeOrder
.Same
:
1384 switch (expr
.AggregationType
) {
1385 case AggregationType
.Union
:
1387 if (!lseq
.MoveNext ())
1388 leftFinished
= true;
1390 case AggregationType
.Intersect
:
1392 case AggregationType
.Except
:
1396 case XmlNodeOrder
.Before
:
1398 if (expr
.AggregationType
== AggregationType
.Intersect
)
1401 default: // After, Unknown
1403 if (expr
.AggregationType
== AggregationType
.Intersect
)
1409 public override XPathItem CurrentCore
{
1410 get { return left ? lseq.Current : rseq.Current; }
1414 internal class AtomizingIterator
: XPathSequence
1418 public AtomizingIterator (XPathSequence iter
)
1419 : base (iter
.Context
)
1424 private AtomizingIterator (AtomizingIterator 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
{
1442 XPathNavigator nav
= iter
.Current
as XPathNavigator
;
1444 return (XPathAtomicValue
) iter
.Current
;
1445 if (nav
.SchemaInfo
!= null)
1446 return new XPathAtomicValue (
1448 nav
.SchemaInfo
.SchemaType
);
1450 return new XPathAtomicValue (nav
.Value
, null);
1455 internal class ConvertingIterator
: XPathSequence
1460 public ConvertingIterator (XPathSequence iter
, SequenceType type
)
1461 : base (iter
.Context
)
1467 private ConvertingIterator (ConvertingIterator other
)
1470 iter
= other
.iter
.Clone ();
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
1494 public TracingIterator (XPathSequence iter
, string format
)
1495 : base (iter
.Context
)
1498 this.format
= format
;
1501 private TracingIterator (TracingIterator 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 ())
1517 // FIXME: use OnMessageEvent
1518 string output
= String
.Format (format
, iter
.Current
.TypedValue
);
1519 Context
.StaticContext
.OnMessageEvent (iter
.Current
, new QueryEventArgs (output
));
1523 public override XPathItem CurrentCore
{
1524 get { return iter.Current; }
1528 internal class QueryEventArgs
1532 public QueryEventArgs (string msg
)
1537 public string Message
{
1542 internal class ListIterator
: XPathSequence
1546 public ListIterator (XQueryContext ctx
, IList list
)
1549 if (list
is ICloneable
)
1552 throw new InvalidOperationException (String
.Format ("XQuery internal error: target list is not cloneable. List is {0}.", list
!= null ? list
.GetType ().ToString () : "null argument"));
1555 private ListIterator (ListIterator other
)
1558 this.list
= (IList
) ((ICloneable
) other
.list
).Clone ();
1561 public override XPathSequence
Clone ()
1563 return new ListIterator (this);
1566 protected override bool MoveNextCore ()
1568 return (Position
< list
.Count
);
1571 public override XPathItem CurrentCore
{
1572 get { return (XPathItem) list [Position - 1]; }
1576 internal class EnumeratorIterator
: XPathSequence
1580 public EnumeratorIterator (XQueryContext ctx
, IEnumerable en
)
1583 list
= en
.GetEnumerator ();
1584 if (list
is ICloneable
)
1587 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"));
1590 private EnumeratorIterator (EnumeratorIterator other
)
1593 this.list
= (IEnumerator
) ((ICloneable
) other
.list
).Clone ();
1596 public override XPathSequence
Clone ()
1598 return new EnumeratorIterator (this);
1601 protected override bool MoveNextCore ()
1603 return list
.MoveNext ();
1606 public override XPathItem CurrentCore
{
1607 get { return (XPathItem) list.Current; }
1611 internal abstract class WrapperIterator
: XPathSequence
1613 XPathSequence source
;
1615 public WrapperIterator (XPathSequence source
)
1616 : base (source
.Context
)
1618 this.source
= source
;
1621 protected WrapperIterator (WrapperIterator other
, bool flag
)
1624 source
= other
.source
.Clone ();
1627 public XPathSequence Source
{
1628 get { return source; }
1631 public override XPathItem CurrentCore
{
1632 get { return source.Current; }
1636 internal class RemovalIterator
: WrapperIterator
1640 public RemovalIterator (XPathSequence source
, int position
)
1643 this.position
= position
;
1646 protected RemovalIterator (RemovalIterator other
)
1647 : base (other
, true)
1649 position
= other
.position
;
1652 public override XPathSequence
Clone ()
1654 return new RemovalIterator (this);
1657 protected override bool MoveNextCore ()
1659 if (!Source
.MoveNext ())
1661 else if (Source
.Position
== position
) // skip target
1662 return Source
.MoveNext ();
1668 internal class InsertingIterator
: WrapperIterator
1671 XPathSequence inserts
;
1672 bool sourceFinished
;
1673 bool insertsFinished
;
1674 XPathSequence currentSequence
;
1676 public InsertingIterator (XPathSequence target
, int position
, XPathSequence inserts
)
1679 this.position
= position
;
1680 this.inserts
= inserts
;
1681 currentSequence
= target
;
1684 protected InsertingIterator (InsertingIterator other
)
1687 position
= other
.position
;
1688 inserts
= other
.inserts
.Clone ();
1689 sourceFinished
= other
.sourceFinished
;
1690 insertsFinished
= other
.insertsFinished
;
1692 other
.inserts
== other
.currentSequence
?
1696 public override XPathSequence
Clone ()
1698 return new InsertingIterator (this);
1701 protected override bool MoveNextCore ()
1703 if (insertsFinished
&& sourceFinished
)
1705 if (sourceFinished
) { // position >= source.Count
1706 currentSequence
= inserts
;
1707 if (inserts
.MoveNext ())
1709 insertsFinished
= true;
1712 else if (insertsFinished
) { // after insertion
1713 if (Source
.MoveNext ())
1715 sourceFinished
= true;
1718 else if (Position
>= position
- 1) {
1719 currentSequence
= inserts
;
1720 if (inserts
.MoveNext ())
1722 currentSequence
= Source
;
1723 insertsFinished
= true;
1725 if (Source
.MoveNext ())
1727 sourceFinished
= true;
1728 return MoveNextCore ();
1731 public override XPathItem CurrentCore
{
1732 get { return currentSequence.Current; }
1736 internal class DistinctValueIterator
: XPathSequence
1738 XPathSequence items
;
1739 CultureInfo collation
;
1740 Hashtable table
= new Hashtable ();
1742 public DistinctValueIterator (XQueryContext ctx
, XPathSequence items
, CultureInfo collation
)
1746 this.collation
= collation
;
1749 protected DistinctValueIterator (DistinctValueIterator other
)
1752 items
= other
.items
.Clone ();
1753 collation
= other
.collation
;
1754 table
= (Hashtable
) other
.table
.Clone ();
1757 public override XPathSequence
Clone ()
1759 return new DistinctValueIterator (this);
1762 protected override bool MoveNextCore ()
1764 if (!items
.MoveNext ())
1766 // FIXME: use collations
1767 // FIXME: check if it really works (esp. Uri et.al)
1768 if (table
.Contains (items
.Current
.TypedValue
))
1769 return MoveNextCore ();
1773 public override XPathItem CurrentCore
{
1774 get { return items.Current; }