//
// Author:
// Piers Haken (piersh@friskit.com)
+// Atsushi Enomoto (atsushi@ximian.com)
//
// (C) 2002 Piers Haken
+// (C) 2003 Atsushi Enomoto
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Xml.XPath;
using System.Xml.Xsl;
+#if NET_2_0
+using NSResolver = System.Xml.IXmlNamespaceResolver;
+#else
+using NSResolver = System.Xml.XmlNamespaceManager;
+#endif
+
namespace System.Xml.XPath
{
internal abstract class BaseIterator : XPathNodeIterator
{
- private XmlNamespaceManager _nsm;
+ NSResolver _nsm;
+ int position;
internal BaseIterator (BaseIterator other)
{
_nsm = other._nsm;
+ position = other.position;
}
- internal BaseIterator (XmlNamespaceManager nsm)
+ internal BaseIterator (NSResolver nsm)
{
_nsm = nsm;
}
- public XmlNamespaceManager NamespaceManager
+ public NSResolver NamespaceManager
{
get { return _nsm; }
set { _nsm = value; }
}
+ public virtual bool ReverseAxis {
+ get { return false; }
+ }
+
+ public abstract bool RequireSorting { get; }
+
+ public virtual int ComparablePosition {
+ get {
+ if (ReverseAxis) {
+ int diff = Count - CurrentPosition + 1;
+ return diff < 1 ? 1 : diff;
+ }
+ else
+ return CurrentPosition;
+ }
+ }
+
+ public override int CurrentPosition {
+ get { return position; }
+ }
+
+ public override bool MoveNext ()
+ {
+ if (!MoveNextCore ())
+ return false;
+ position++;
+ return true;
+ }
+
+ public abstract bool MoveNextCore ();
+
public override string ToString ()
{
if (Current != null)
}
}
- internal class MergedIterator : BaseIterator
+ internal class WrapperIterator : BaseIterator
{
- protected ArrayList _iters = new ArrayList ();
- protected int _pos;
- protected int _index;
+ XPathNodeIterator iter;
- public MergedIterator (BaseIterator iter ) : base (iter) {}
- protected MergedIterator (MergedIterator other) : base (other)
+ public WrapperIterator (XPathNodeIterator iter, NSResolver nsm)
+ : base (nsm)
{
- foreach (object obj in other._iters)
- _iters.Add (obj);
- _pos = other._pos;
- _index = other._index;
+ this.iter = iter;
}
- public override XPathNodeIterator Clone () { return new MergedIterator (this); }
- public void Add (BaseIterator iter)
+ private WrapperIterator (WrapperIterator other)
+ : base (other)
{
- _iters.Add (iter);
+ iter = other.iter.Clone ();
}
- public override bool MoveNext ()
+ public override XPathNodeIterator Clone ()
{
- while (_index < _iters.Count)
- {
- BaseIterator iter = (BaseIterator) _iters [_index];
- if (iter.MoveNext ())
- {
- _pos ++;
- return true;
- }
- _index ++;
- }
- return false;
+ return new WrapperIterator (this);
}
- public override XPathNavigator Current
+
+ public override bool MoveNextCore ()
{
- get
- {
- if (_index >= _iters.Count)
- return null;
- BaseIterator iter = (BaseIterator) _iters [_index];
- return iter.Current;
- }
+ return iter.MoveNext ();
+ }
+
+ public override XPathNavigator Current {
+ get { return iter.Current; }
+ }
+
+ public override bool RequireSorting {
+ get { return true; }
}
- public override int CurrentPosition { get { return _pos; }}
}
internal abstract class SimpleIterator : BaseIterator
{
- protected XPathNavigator _nav;
- protected int _pos;
+ protected readonly BaseIterator _iter;
+ protected readonly XPathNavigator _nav;
+ protected XPathNavigator _current;
- public SimpleIterator (BaseIterator iter) : base (iter)
+ public SimpleIterator (BaseIterator iter) : base (iter.NamespaceManager)
{
+ _iter = iter;
_nav = iter.Current.Clone ();
}
- protected SimpleIterator (SimpleIterator other) : base (other)
+ protected SimpleIterator (SimpleIterator other, bool clone) : base (other)
{
- _nav = other._nav.Clone ();
- _pos = other._pos;
+ if (other._nav == null)
+ _iter = (BaseIterator) other._iter.Clone ();
+ else
+ _nav = other._nav.Clone ();
}
- public SimpleIterator (XPathNavigator nav, XmlNamespaceManager nsm) : base (nsm)
+ public SimpleIterator (XPathNavigator nav, NSResolver nsm) : base (nsm)
{
_nav = nav.Clone ();
}
- public override XPathNavigator Current { get { return _nav; }}
- public override int CurrentPosition { get { return _pos; }}
+ public override XPathNavigator Current {
+ get {
+ if (_current == null) // position == 0
+ _current = _nav.Clone ();
+ return _current;
+ }
+ }
}
internal class SelfIterator : SimpleIterator
{
public SelfIterator (BaseIterator iter) : base (iter) {}
- public SelfIterator (XPathNavigator nav, XmlNamespaceManager nsm) : base (nav, nsm) {}
- protected SelfIterator (SimpleIterator other) : base (other) {}
- public override XPathNodeIterator Clone () { return new SelfIterator (this); }
- public override bool MoveNext ()
+ public SelfIterator (XPathNavigator nav, NSResolver nsm) : base (nav, nsm) {}
+ protected SelfIterator (SelfIterator other, bool clone) : base (other, true)
+ {
+ if (other._current != null)
+ _current = _nav;
+ }
+
+ public override XPathNodeIterator Clone () { return new SelfIterator (this, true); }
+ public override bool MoveNextCore ()
{
- if (_pos == 0)
+ if (CurrentPosition == 0)
{
- _pos = 1;
+ _current = _nav;
return true;
}
return false;
}
+
+ public override bool RequireSorting { get { return false; } }
}
internal class NullIterator : SelfIterator
{
public NullIterator (BaseIterator iter) : base (iter) {}
public NullIterator (XPathNavigator nav) : this (nav, null) {}
- public NullIterator (XPathNavigator nav, XmlNamespaceManager nsm) : base (nav, nsm) {}
- protected NullIterator (SimpleIterator other) : base (other) {}
+ public NullIterator (XPathNavigator nav, NSResolver nsm) : base (nav, nsm) {}
+ private NullIterator (NullIterator other) : base (other, true) {}
public override XPathNodeIterator Clone () { return new NullIterator (this); }
- public override bool MoveNext ()
+ public override bool MoveNextCore ()
{
return false;
}
}
+ internal class ParensIterator : BaseIterator
+ {
+ BaseIterator _iter;
+ public ParensIterator (BaseIterator iter) : base (iter.NamespaceManager)
+ {
+ _iter = iter;
+ }
+ private ParensIterator (ParensIterator other) : base (other)
+ {
+ _iter = (BaseIterator) other._iter.Clone ();
+ }
+ public override XPathNodeIterator Clone () { return new ParensIterator (this); }
+ public override bool MoveNextCore ()
+ {
+ return _iter.MoveNext ();
+ }
+
+ public override XPathNavigator Current { get { return _iter.Current; }}
+
+ public override bool RequireSorting { get { return _iter.RequireSorting; } }
+
+ public override int Count { get { return _iter.Count; } }
+ }
+
internal class ParentIterator : SimpleIterator
{
public ParentIterator (BaseIterator iter) : base (iter) {}
- protected ParentIterator (SimpleIterator other) : base (other) {}
+ private ParentIterator (ParentIterator other) : base (other, true)
+ {
+ if (other._current != null)
+ _current = _nav;
+ }
+ public ParentIterator (XPathNavigator nav, NSResolver nsm) : base (nav, nsm) {}
public override XPathNodeIterator Clone () { return new ParentIterator (this); }
- public override bool MoveNext ()
+ public override bool MoveNextCore ()
{
- if (_pos == 0 && _nav.MoveToParent ())
+ if (CurrentPosition == 0 && _nav.MoveToParent ())
{
- _pos = 1;
+ _current = _nav;
return true;
}
return false;
}
+
+ public override bool ReverseAxis { get { return true; } }
+
+ public override bool RequireSorting { get { return false; } }
}
internal class ChildIterator : SimpleIterator
{
public ChildIterator (BaseIterator iter) : base (iter) {}
- protected ChildIterator (SimpleIterator other) : base (other) {}
+ private ChildIterator (ChildIterator other) : base (other, true) {}
public override XPathNodeIterator Clone () { return new ChildIterator (this); }
- public override bool MoveNext ()
+ public override bool MoveNextCore ()
{
- bool fSuccess = (_pos == 0) ? _nav.MoveToFirstChild () : _nav.MoveToNext ();
- if (fSuccess)
- _pos ++;
+ bool fSuccess = (CurrentPosition == 0) ? _nav.MoveToFirstChild () : _nav.MoveToNext ();
+ if (fSuccess) {
+ _current = null;
+ }
return fSuccess;
}
+
+ public override bool RequireSorting { get { return false; } }
}
internal class FollowingSiblingIterator : SimpleIterator
{
public FollowingSiblingIterator (BaseIterator iter) : base (iter) {}
- protected FollowingSiblingIterator (SimpleIterator other) : base (other) {}
+ private FollowingSiblingIterator (FollowingSiblingIterator other) : base (other, true) {}
public override XPathNodeIterator Clone () { return new FollowingSiblingIterator (this); }
- public override bool MoveNext ()
+ public override bool MoveNextCore ()
{
+ switch (_nav.NodeType) {
+ case XPathNodeType.Attribute:
+ case XPathNodeType.Namespace:
+ // They have no siblings.
+ return false;
+ }
if (_nav.MoveToNext ())
{
- _pos ++;
+ _current = null;
return true;
}
return false;
}
+
+ public override bool RequireSorting { get { return false; } }
}
internal class PrecedingSiblingIterator : SimpleIterator
{
- public PrecedingSiblingIterator (BaseIterator iter) : base (iter) {}
- protected PrecedingSiblingIterator (SimpleIterator other) : base (other) {}
+ bool finished;
+ bool started;
+ XPathNavigator startPosition;
+
+ public PrecedingSiblingIterator (BaseIterator iter) : base (iter)
+ {
+ startPosition = iter.Current.Clone ();
+ }
+ private PrecedingSiblingIterator (PrecedingSiblingIterator other) : base (other, true)
+ {
+ startPosition = other.startPosition;
+ started = other.started;
+ finished = other.finished;
+ }
+
public override XPathNodeIterator Clone () { return new PrecedingSiblingIterator (this); }
- public override bool MoveNext ()
+ public override bool MoveNextCore ()
{
- if (_nav.MoveToPrevious ())
- {
- _pos ++;
+ if (finished)
+ return false;
+ if (!started) {
+ started = true;
+ switch (_nav.NodeType) {
+ case XPathNodeType.Attribute:
+ case XPathNodeType.Namespace:
+ // They have no siblings.
+ finished = true;
+ return false;
+ }
+
+ _nav.MoveToFirst ();
+ if (!_nav.IsSamePosition (startPosition)) {
+ _current = null;
+ return true;
+ }
+ } else {
+ if (!_nav.MoveToNext ()) {
+ finished = true;
+ return false;
+ }
+ }
+ if (_nav.ComparePosition (startPosition) != XmlNodeOrder.Before) {
+ // Note that if _nav contains only 1 node, it won't be Same.
+ finished = true;
+ return false;
+ } else {
+ _current = null;
return true;
}
- return false;
}
+ public override bool ReverseAxis {
+ get { return true; }
+ }
+
+ public override bool RequireSorting { get { return true; } }
}
internal class AncestorIterator : SimpleIterator
{
- public AncestorIterator (BaseIterator iter) : base (iter) {}
- protected AncestorIterator (SimpleIterator other) : base (other) {}
- public override XPathNodeIterator Clone () { return new AncestorIterator (this); }
- public override bool MoveNext ()
+ int currentPosition;
+ ArrayList navigators;
+ XPathNavigator startPosition;
+
+ public AncestorIterator (BaseIterator iter) : base (iter)
{
- if (_nav.MoveToParent ())
- {
- _pos ++;
- return true;
+ startPosition = iter.Current.Clone ();
+ }
+
+ private AncestorIterator (AncestorIterator other)
+ : base (other, true)
+ {
+ startPosition = other.startPosition;
+ if (other.navigators != null)
+ navigators = (ArrayList) other.navigators.Clone ();
+ currentPosition = other.currentPosition;
+ }
+
+ public override XPathNodeIterator Clone ()
+ {
+ return new AncestorIterator (this);
+ }
+
+ private void CollectResults ()
+ {
+ navigators = new ArrayList ();
+
+ XPathNavigator ancestors = startPosition.Clone ();
+ if (!ancestors.MoveToParent ())
+ return;
+ while (ancestors.NodeType != XPathNodeType.Root) {
+ navigators.Add (ancestors.Clone ());
+ ancestors.MoveToParent ();
+ }
+ currentPosition = navigators.Count;
+ }
+
+ public override bool MoveNextCore ()
+ {
+ if (navigators == null) {
+ CollectResults ();
+ if (startPosition.NodeType != XPathNodeType.Root) {
+ // First time it returns Root
+ _nav.MoveToRoot ();
+ _current = null;
+ return true;
+ }
+ }
+ if (currentPosition == 0)
+ return false;
+ _nav.MoveTo ((XPathNavigator) navigators [--currentPosition]);
+ _current = null;
+ return true;
+ }
+
+ public override bool ReverseAxis {
+ get { return true; }
+ }
+
+ public override bool RequireSorting { get { return true; } }
+
+ public override int Count {
+ get {
+ if (navigators == null)
+ CollectResults ();
+ return navigators.Count;
}
- return false;
}
}
- internal class AncestorOrSelfIterator : MergedIterator
+ internal class AncestorOrSelfIterator : SimpleIterator
{
+ int currentPosition;
+ ArrayList navigators;
+ XPathNavigator startPosition;
+
public AncestorOrSelfIterator (BaseIterator iter) : base (iter)
{
- Add (new SelfIterator (iter));
- Add (new AncestorIterator (iter));
+ startPosition = iter.Current.Clone ();
+ }
+
+ private AncestorOrSelfIterator (AncestorOrSelfIterator other)
+ : base (other, true)
+ {
+ startPosition = other.startPosition;
+ if (other.navigators != null)
+ navigators = (ArrayList) other.navigators.Clone ();
+ currentPosition = other.currentPosition;
+ }
+
+ public override XPathNodeIterator Clone ()
+ {
+ return new AncestorOrSelfIterator (this);
+ }
+
+ private void CollectResults ()
+ {
+ navigators = new ArrayList ();
+
+ XPathNavigator ancestors = startPosition.Clone ();
+ if (!ancestors.MoveToParent ())
+ return;
+ while (ancestors.NodeType != XPathNodeType.Root) {
+ navigators.Add (ancestors.Clone ());
+ ancestors.MoveToParent ();
+ }
+ currentPosition = navigators.Count;
+ }
+
+ public override bool MoveNextCore ()
+ {
+ if (navigators == null) {
+ CollectResults ();
+ if (startPosition.NodeType != XPathNodeType.Root) {
+ // First time it returns Root
+ _nav.MoveToRoot ();
+ _current = null;
+ return true;
+ }
+ }
+ if (currentPosition == -1)
+ return false;
+ if (currentPosition-- == 0) {
+ _nav.MoveTo (startPosition);
+ _current = null;
+ return true; // returns self.
+ }
+ _nav.MoveTo ((XPathNavigator) navigators [currentPosition]);
+ _current = null;
+ return true;
+ }
+
+ public override bool ReverseAxis {
+ get { return true; }
+ }
+
+ public override bool RequireSorting { get { return true; } }
+
+ public override int Count {
+ get {
+ if (navigators == null)
+ CollectResults ();
+ return navigators.Count + 1;
+ }
}
- protected AncestorOrSelfIterator (MergedIterator other) : base (other) {}
- public override XPathNodeIterator Clone () { return new AncestorOrSelfIterator (this); }
}
internal class DescendantIterator : SimpleIterator
{
- protected int _depth;
+ private int _depth;
+ private bool _finished;
+
public DescendantIterator (BaseIterator iter) : base (iter) {}
- protected DescendantIterator (SimpleIterator other) : base (other) {}
+
+ private DescendantIterator (DescendantIterator other) : base (other)
+ {
+ _depth = other._depth;
+ _finished = other._finished;
+ }
+
public override XPathNodeIterator Clone () { return new DescendantIterator (this); }
- [MonoTODO]
- public override bool MoveNext ()
+
+ public override bool MoveNextCore ()
{
+ if (_finished)
+ return false;
+
if (_nav.MoveToFirstChild ())
{
_depth ++;
- _pos ++;
+ _current = null;
return true;
}
while (_depth != 0)
{
if (_nav.MoveToNext ())
{
- _pos ++;
+ _current = null;
return true;
}
if (!_nav.MoveToParent ()) // should NEVER fail!
- throw new XPathException ("unexpected depth"); // TODO: better message
+ throw new XPathException ("There seems some bugs on the XPathNavigator implementation class.");
_depth --;
}
+ _finished = true;
return false;
}
+
+ public override bool RequireSorting { get { return false; } }
}
- internal class DescendantOrSelfIterator : MergedIterator
+ internal class DescendantOrSelfIterator : SimpleIterator
{
- public DescendantOrSelfIterator (BaseIterator iter) : base (iter)
+ private int _depth;
+ private bool _finished;
+
+ public DescendantOrSelfIterator (BaseIterator iter) : base (iter) {}
+
+ private DescendantOrSelfIterator (DescendantOrSelfIterator other) : base (other, true)
{
- Add (new SelfIterator (iter));
- Add (new DescendantIterator (iter));
+ _depth = other._depth;
}
- protected DescendantOrSelfIterator (MergedIterator other) : base (other) {}
+
public override XPathNodeIterator Clone () { return new DescendantOrSelfIterator (this); }
+
+ public override bool MoveNextCore ()
+ {
+ if (_finished)
+ return false;
+
+ if (CurrentPosition == 0)
+ {
+ // self
+ _current = null;
+ return true;
+ }
+ if (_nav.MoveToFirstChild ())
+ {
+ _depth ++;
+ _current = null;
+ return true;
+ }
+ while (_depth != 0)
+ {
+ if (_nav.MoveToNext ())
+ {
+ _current = null;
+ return true;
+ }
+ if (!_nav.MoveToParent ()) // should NEVER fail!
+ throw new XPathException ("There seems some bugs on the XPathNavigator implementation class.");
+ _depth --;
+ }
+ _finished = true;
+ return false;
+ }
+
+ public override bool RequireSorting { get { return false; } }
}
internal class FollowingIterator : SimpleIterator
{
+ private bool _finished = false;
public FollowingIterator (BaseIterator iter) : base (iter) {}
- protected FollowingIterator (SimpleIterator other) : base (other) {}
+ private FollowingIterator (FollowingIterator other) : base (other, true) {}
public override XPathNodeIterator Clone () { return new FollowingIterator (this); }
- public override bool MoveNext ()
+ public override bool MoveNextCore ()
{
- if (_pos == 0)
+ if (_finished)
+ return false;
+ if (CurrentPosition == 0)
{
if (_nav.MoveToNext ())
{
- _pos ++;
+ _current = null;
return true;
+ } else {
+ while (_nav.MoveToParent ()) {
+ if (_nav.MoveToNext ()) {
+ _current = null;
+ return true;
+ }
+ }
}
}
else
{
if (_nav.MoveToFirstChild ())
{
- _pos ++;
+ _current = null;
return true;
}
do
{
if (_nav.MoveToNext ())
{
- _pos ++;
+ _current = null;
return true;
}
}
while (_nav.MoveToParent ());
}
+ _finished = true;
return false;
}
+
+ public override bool RequireSorting { get { return false; } }
}
internal class PrecedingIterator : SimpleIterator
{
- public PrecedingIterator (BaseIterator iter) : base (iter) {}
- protected PrecedingIterator (SimpleIterator other) : base (other) {}
+ bool finished;
+ bool started;
+ XPathNavigator startPosition;
+
+ public PrecedingIterator (BaseIterator iter) : base (iter)
+ {
+ startPosition = iter.Current.Clone ();
+ }
+ private PrecedingIterator (PrecedingIterator other) : base (other, true)
+ {
+ startPosition = other.startPosition;
+ started = other.started;
+ finished = other.finished;
+ }
public override XPathNodeIterator Clone () { return new PrecedingIterator (this); }
- public override bool MoveNext ()
+ public override bool MoveNextCore ()
{
- if (_pos == 0)
- {
- if (_nav.MoveToPrevious ())
- {
- _pos ++;
- return true;
- }
+ if (finished)
+ return false;
+ if (!started) {
+ started = true;
+ _nav.MoveToRoot ();
}
- else
- {
- if (_nav.MoveToFirstChild ())
- {
- while (_nav.MoveToNext ())
- ;
- _pos ++;
- return true;
- }
- do
- {
- if (_nav.MoveToPrevious ())
- {
- _pos ++;
- return true;
+ bool loop = true;
+ while (loop) {
+ while (!_nav.MoveToFirstChild ()) {
+ while (!_nav.MoveToNext ()) {
+ if (!_nav.MoveToParent ()) { // Should not finish, at least before startPosition.
+ finished = true;
+ return false;
+ }
}
+ break;
}
- while (_nav.MoveToParent ());
+ if (_nav.IsDescendant (startPosition))
+ continue;
+ loop = false;
+ break;
+ }
+ if (_nav.ComparePosition (startPosition) != XmlNodeOrder.Before) {
+ // Note that if _nav contains only 1 node, it won't be Same.
+ finished = true;
+ return false;
+ } else {
+ _current = null;
+ return true;
}
- return false;
}
+ public override bool ReverseAxis {
+ get { return true; }
+ }
+
+ public override bool RequireSorting { get { return true; } }
}
internal class NamespaceIterator : SimpleIterator
{
public NamespaceIterator (BaseIterator iter) : base (iter) {}
- protected NamespaceIterator (SimpleIterator other) : base (other) {}
+ private NamespaceIterator (NamespaceIterator other) : base (other, true) {}
public override XPathNodeIterator Clone () { return new NamespaceIterator (this); }
- public override bool MoveNext ()
+ public override bool MoveNextCore ()
{
- if (_pos == 0)
+ if (CurrentPosition == 0)
{
if (_nav.MoveToFirstNamespace ())
{
- _pos ++;
+ _current = null;
return true;
}
}
else if (_nav.MoveToNextNamespace ())
{
- _pos ++;
+ _current = null;
return true;
}
return false;
}
+
+ public override bool ReverseAxis { get { return true; } }
+ public override bool RequireSorting { get { return false; } }
}
internal class AttributeIterator : SimpleIterator
{
public AttributeIterator (BaseIterator iter) : base (iter) {}
- protected AttributeIterator (SimpleIterator other) : base (other) {}
+ private AttributeIterator (AttributeIterator other) : base (other, true) {}
public override XPathNodeIterator Clone () { return new AttributeIterator (this); }
- public override bool MoveNext ()
+ public override bool MoveNextCore ()
{
- if (_pos == 0)
+ if (CurrentPosition == 0)
{
if (_nav.MoveToFirstAttribute ())
{
- _pos += 1;
+ _current = null;
return true;
}
}
else if (_nav.MoveToNextAttribute ())
{
- _pos ++;
+ _current = null;
return true;
}
return false;
}
+
+ public override bool RequireSorting { get { return false; } }
}
internal class AxisIterator : BaseIterator
{
- protected BaseIterator _iter;
- protected NodeTest _test;
- protected int _pos;
+ private SimpleIterator _iter;
+ private NodeTest _test;
+
+ string name, ns;
+ XPathNodeType matchType;
- public AxisIterator (BaseIterator iter, NodeTest test) : base (iter)
+ public AxisIterator (SimpleIterator iter, NodeTest test) : base (iter.NamespaceManager)
{
_iter = iter;
_test = test;
+ test.GetInfo (out name, out ns, out matchType, NamespaceManager);
+// if (name != null)
+// name = Current.NameTable.Add (name);
+
+// if (ns != null)
+// ns = Current.NameTable.Add (ns);
}
- protected AxisIterator (AxisIterator other) : base (other)
+ private AxisIterator (AxisIterator other) : base (other)
{
- _iter = (BaseIterator) other._iter.Clone ();
+ _iter = (SimpleIterator) other._iter.Clone ();
_test = other._test;
- _pos = other._pos;
+ name = other.name;
+ ns = other.ns;
+ matchType = other.matchType;
}
public override XPathNodeIterator Clone () { return new AxisIterator (this); }
- public override bool MoveNext ()
+ public override bool MoveNextCore ()
{
while (_iter.MoveNext ())
{
if (_test.Match (NamespaceManager, Current))
{
- _pos ++;
return true;
}
}
return false;
}
public override XPathNavigator Current { get { return _iter.Current; }}
- public override int CurrentPosition { get { return _pos; }}
+
+ bool Match ()
+ {
+ if (Current.NodeType != matchType && matchType != XPathNodeType.All)
+ return false;
+
+ if (ns == null)
+ return name == null || (object)name == (object)Current.LocalName;
+ else
+ return (object)ns == (object)Current.NamespaceURI &&
+ (name == null || (object)name == (object)Current.LocalName);
+ }
+ public override bool ReverseAxis {
+ get { return _iter.ReverseAxis; }
+ }
+
+ public override bool RequireSorting { get { return _iter.RequireSorting; } }
}
internal class SlashIterator : BaseIterator
{
- protected BaseIterator _iterLeft;
- protected BaseIterator _iterRight;
- protected NodeSet _expr;
- protected int _pos;
+ private BaseIterator _iterLeft;
+ private BaseIterator _iterRight;
+ private NodeSet _expr;
+ ArrayList _navStore;
+ SortedList _iterList;
+ bool _finished;
+ BaseIterator _nextIterRight;
- public SlashIterator (BaseIterator iter, NodeSet expr) : base (iter)
+ public SlashIterator (BaseIterator iter, NodeSet expr) : base (iter.NamespaceManager)
{
_iterLeft = iter;
_expr = expr;
+ if (_iterLeft.RequireSorting || _expr.RequireSorting)
+ CollectResults ();
}
- protected SlashIterator (SlashIterator other) : base (other)
+ private SlashIterator (SlashIterator other) : base (other)
{
_iterLeft = (BaseIterator) other._iterLeft.Clone ();
if (other._iterRight != null)
_iterRight = (BaseIterator) other._iterRight.Clone ();
_expr = other._expr;
- _pos = other._pos;
+ if (other._iterList != null)
+ _iterList = (SortedList) other._iterList.Clone ();
+ if (other._navStore != null)
+ _navStore = (ArrayList) other._navStore.Clone ();
+ _finished = other._finished;
+ if (other._nextIterRight != null)
+ _nextIterRight = (BaseIterator) other._nextIterRight.Clone ();
}
public override XPathNodeIterator Clone () { return new SlashIterator (this); }
- public override bool MoveNext ()
+ public override bool MoveNextCore ()
{
- while (_iterRight == null || !_iterRight.MoveNext ())
- {
+ if (_finished)
+ return false;
+ if (_navStore != null) {
+ // Which requires sorting::
+ if (_navStore.Count < CurrentPosition + 1) {
+ _finished = true;
+ return false;
+ }
+ while (_navStore.Count > CurrentPosition + 1) {
+ if (((XPathNavigator) _navStore [CurrentPosition + 1]).IsSamePosition (
+ (XPathNavigator) _navStore [CurrentPosition]))
+ _navStore.RemoveAt (CurrentPosition + 1);
+ else
+ break;
+ }
+
+ return true;
+ }
+ // Which does not require sorting::
+
+ if (_iterRight == null) { // First time
if (!_iterLeft.MoveNext ())
return false;
_iterRight = _expr.EvaluateNodeSet (_iterLeft);
+ _iterList = new SortedList (XPathIteratorComparer.Instance);
+ }
+
+ while (true) {
+ while (!_iterRight.MoveNext ()) {
+ if (_iterList.Count > 0) {
+ int last = _iterList.Count - 1;
+ BaseIterator tmpIter = (BaseIterator) _iterList.GetByIndex (last);
+ _iterList.RemoveAt (last);
+ switch (tmpIter.Current.ComparePosition (_iterRight.Current)) {
+ case XmlNodeOrder.Same:
+ case XmlNodeOrder.Before:
+ _iterRight = tmpIter;
+ continue;
+ default:
+ _iterRight = tmpIter;
+ break;
+ }
+ break;
+ } else if (_nextIterRight != null) {
+ _iterRight = _nextIterRight;
+ _nextIterRight = null;
+ break;
+ } else if (!_iterLeft.MoveNext ()) {
+ _finished = true;
+ return false;
+ }
+ else
+ _iterRight = _expr.EvaluateNodeSet (_iterLeft);
+ }
+ bool loop = true;
+ while (loop) {
+ loop = false;
+ if (_nextIterRight == null) {
+ bool noMoreNext = false;
+ while (_nextIterRight == null || !_nextIterRight.MoveNext ()) {
+ if(_iterLeft.MoveNext ())
+ _nextIterRight = _expr.EvaluateNodeSet (_iterLeft);
+ else {
+ noMoreNext = true;
+ break;
+ }
+ }
+ if (noMoreNext)
+ _nextIterRight = null; // FIXME: More efficient code. Maybe making noMoreNext class scope would be better.
+ }
+ if (_nextIterRight != null) {
+ switch (_iterRight.Current.ComparePosition (_nextIterRight.Current)) {
+ case XmlNodeOrder.After:
+ _iterList.Add (_iterList.Count, _iterRight);
+ _iterRight = _nextIterRight;
+ _nextIterRight = null;
+ loop = true;
+ break;
+ case XmlNodeOrder.Same:
+ if (!_nextIterRight.MoveNext ())
+ _nextIterRight = null;
+
+ else {
+ int last = _iterList.Count;
+ if (last > 0) {
+ _iterList.Add (last, _nextIterRight);
+ _nextIterRight = (BaseIterator) _iterList.GetByIndex (last);
+ _iterList.RemoveAt (last);
+ }
+ }
+
+ loop = true;
+ break;
+ }
+ }
+ }
+ return true;
+ }
+ }
+
+ private void CollectResults ()
+ {
+ _navStore = new ArrayList ();
+ while (true) {
+ while (_iterRight == null || !_iterRight.MoveNext ()) {
+ if (!_iterLeft.MoveNext ()) {
+ _navStore.Sort (XPathNavigatorComparer.Instance);
+ return;
+ }
+ _iterRight = _expr.EvaluateNodeSet (_iterLeft);
+ }
+ XPathNavigator nav = _iterRight.Current;
+ _navStore.Add (nav);
}
- _pos ++;
- return true;
}
+
public override XPathNavigator Current {
- get {
- if (_iterRight == null) return null;
-
- return _iterRight.Current;
+ get {
+ if (CurrentPosition <= 0) return null;
+ if (_navStore != null) {
+ return (XPathNavigator) _navStore [CurrentPosition - 1];
+ } else {
+ return _iterRight.Current;
+ }
}
}
- public override int CurrentPosition { get { return _pos; }}
+
+ public override bool RequireSorting {
+ // It always does not need to be sorted.
+ get { return false; }
+ }
+
+ public override int Count { get { return _navStore == null ? base.Count : _navStore.Count; } }
}
internal class PredicateIterator : BaseIterator
{
- protected BaseIterator _iter;
- protected Expression _pred;
- protected int _pos;
+ private BaseIterator _iter;
+ private Expression _pred;
+ private XPathResultType resType;
- public PredicateIterator (BaseIterator iter, Expression pred) : base (iter)
+ public PredicateIterator (BaseIterator iter, Expression pred) : base (iter.NamespaceManager)
{
_iter = iter;
_pred = pred;
+ resType = pred.GetReturnType (iter);
}
- protected PredicateIterator (PredicateIterator other) : base (other)
+ private PredicateIterator (PredicateIterator other) : base (other)
{
_iter = (BaseIterator) other._iter.Clone ();
_pred = other._pred;
- _pos = other._pos;
+ resType = other.resType;
}
public override XPathNodeIterator Clone () { return new PredicateIterator (this); }
- public override bool MoveNext ()
+ public override bool MoveNextCore ()
{
while (_iter.MoveNext ())
{
- bool fTrue = true;
- object result = _pred.Evaluate ((BaseIterator) _iter.Clone ());
- if (result is double)
- {
- if ((double) result != _iter.CurrentPosition)
- continue;
+ switch (resType) {
+ case XPathResultType.Number:
+ if (_pred.EvaluateNumber (_iter) != _iter.ComparablePosition)
+ continue;
+ break;
+ case XPathResultType.Any: {
+ object result = _pred.Evaluate (_iter);
+ if (result is double)
+ {
+ if ((double) result != _iter.ComparablePosition)
+ continue;
+ }
+ else if (!XPathFunctions.ToBoolean (result))
+ continue;
+ }
+ break;
+ default:
+ if (!_pred.EvaluateBoolean (_iter))
+ continue;
+ break;
}
- else if (!XPathFunctions.ToBoolean (result))
- continue;
- _pos ++;
return true;
}
return false;
}
public override XPathNavigator Current { get { return _iter.Current; }}
- public override int CurrentPosition { get { return _pos; }}
+ public override bool ReverseAxis {
+ get { return _iter.ReverseAxis; }
+ }
+
+ public override bool RequireSorting { get { return _iter.RequireSorting || _pred.RequireSorting; } }
}
- internal class EnumeratorIterator : BaseIterator
+ internal class ListIterator : BaseIterator
{
- protected IEnumerator _enum;
- protected int _pos;
+ private IList _list;
+ bool _requireSorting;
- public EnumeratorIterator (BaseIterator iter, IEnumerator enumerator) : base (iter)
+ public ListIterator (BaseIterator iter, IList list, bool requireSorting) : base (iter.NamespaceManager)
+ {
+ if (!(list is ICloneable))
+ throw new ArgumentException ("Target enumerator must be cloneable.");
+ _list = list;
+ _requireSorting = requireSorting;
+ }
+
+ public ListIterator (IList list, NSResolver nsm, bool requireSorting) : base (nsm)
{
- _enum = enumerator;
+ if (!(list is ICloneable))
+ throw new ArgumentException ("Target enumerator must be cloneable.");
+ _list = list;
+ _requireSorting = requireSorting;
}
- protected EnumeratorIterator (EnumeratorIterator other) : base (other)
+ private ListIterator (ListIterator other) : base (other)
{
- _enum = other._enum;
- _pos = other._pos;
+ ICloneable listClone = other._list as ICloneable;
+ _list = (IList) listClone.Clone ();
+ _requireSorting = other._requireSorting;
}
- public override XPathNodeIterator Clone () { return new EnumeratorIterator (this); }
+ public override XPathNodeIterator Clone () { return new ListIterator (this); }
- public override bool MoveNext ()
+ public override bool MoveNextCore ()
{
- if (!_enum.MoveNext ())
+ if (CurrentPosition >= _list.Count)
return false;
- _pos++;
return true;
}
- public override XPathNavigator Current { get { return (XPathNavigator) _enum.Current; }}
- public override int CurrentPosition { get { return _pos; }}
- }
+ public override XPathNavigator Current {
+ get {
+ if (_list.Count == 0)
+ return null;
+ return (XPathNavigator) _list [CurrentPosition - 1];
+ }
+ }
+ public override bool RequireSorting { get { return _requireSorting; } }
+ public override int Count { get { return _list.Count; } }
+ }
+
+
internal class UnionIterator : BaseIterator
{
- protected ArrayList _rgNodes;
- protected BaseIterator _left, _right;
- protected int _pos;
+ private BaseIterator _left, _right;
+ private bool keepLeft;
+ private bool keepRight;
+ private bool useRight;
- public UnionIterator (BaseIterator iter, BaseIterator left, BaseIterator right) : base (iter)
+ public UnionIterator (BaseIterator iter, BaseIterator left, BaseIterator right) : base (iter.NamespaceManager)
{
- _rgNodes = new ArrayList ();
_left = left;
_right = right;
}
- protected UnionIterator (UnionIterator other) : base (other)
+ private UnionIterator (UnionIterator other) : base (other)
{
- _rgNodes = (ArrayList) other._rgNodes.Clone ();
- _left = other._left;
- _right = other._right;
- _pos = other._pos;
+ _left = (BaseIterator) other._left.Clone ();
+ _right = (BaseIterator) other._right.Clone ();
+ keepLeft = other.keepLeft;
+ keepRight = other.keepRight;
+ useRight = other.useRight;
}
public override XPathNodeIterator Clone () { return new UnionIterator (this); }
- public override bool MoveNext ()
+ public override bool MoveNextCore ()
{
- if (_left.MoveNext ())
- {
- _rgNodes.Add (_left.Current.Clone ());
- _pos ++;
+ if (!keepLeft)
+ keepLeft = _left.MoveNext ();
+ if (!keepRight)
+ keepRight = _right.MoveNext ();
+
+ if (!keepLeft && !keepRight)
+ return false;
+
+ if (!keepRight) {
+ keepLeft = useRight = false;
+ return true;
+ } else if (!keepLeft) {
+ keepRight = false;
+ useRight = true;
return true;
}
- while (_right.MoveNext ())
- {
- XPathNavigator navRight = _right.Current;
- bool fFound = false;
- foreach (XPathNavigator navLeft in _rgNodes)
- {
- if (navLeft.IsSamePosition (navRight))
- {
- fFound = true;
- break;
- }
- }
- if (!fFound)
- {
- _pos ++;
- return true;
- }
+ switch (_left.Current.ComparePosition (_right.Current)) {
+ case XmlNodeOrder.Same:
+ // consume both. i.e. don't output duplicate result.
+ keepLeft = keepRight = false;
+ useRight = true;
+ return true;
+ case XmlNodeOrder.Before:
+ case XmlNodeOrder.Unknown: // Maybe happen because of "document(a) | document(b)"
+ keepLeft = useRight = false;
+ return true;
+ case XmlNodeOrder.After:
+ keepRight = false;
+ useRight = true;
+ return true;
+ default:
+ throw new InvalidOperationException ("Should not happen.");
}
- return false;
}
public override XPathNavigator Current
{
get
{
- if (_pos < _rgNodes.Count)
- throw new XPathException ("bug in UnionOperator"); // TODO: better exception
- if (_pos == _rgNodes.Count)
- return _left.Current;
- else
+ if (CurrentPosition == 0)
+ return null;
+ if (useRight)
return _right.Current;
+ else
+ return _left.Current;
}
}
- public override int CurrentPosition { get { return _pos; }}
+
+ public override bool RequireSorting { get { return _left.RequireSorting || _right.RequireSorting; } }
}
}