2 // System.Xml.XPath.XPathNavigator
5 // Jason Diamond (jason@injektilo.org)
7 // (C) 2002 Jason Diamond http://injektilo.org/
13 namespace System.Xml.XPath
15 public abstract class XPathNavigator : ICloneable
19 protected XPathNavigator ()
27 public abstract string BaseURI { get; }
29 public abstract bool HasAttributes { get; }
31 public abstract bool HasChildren { get; }
33 public abstract bool IsEmptyElement { get; }
35 public abstract string LocalName { get; }
37 public abstract string Name { get; }
39 public abstract string NamespaceURI { get; }
41 public abstract XmlNameTable NameTable { get; }
43 public abstract XPathNodeType NodeType { get; }
45 public abstract string Prefix { get; }
47 public abstract string Value { get; }
49 public abstract string XmlLang { get; }
56 XPathNavigator nav = Clone ();
57 while (nav.MoveToParent ())
67 public abstract XPathNavigator Clone ();
69 public virtual XmlNodeOrder ComparePosition (XPathNavigator nav)
71 if (IsSamePosition (nav))
72 return XmlNodeOrder.Same;
74 XPathNavigator nav1 = Clone ();
75 XPathNavigator nav2 = nav.Clone ();
77 int nDepth1 = nav1.Depth;
78 int nDepth2 = nav2.Depth;
80 if (nDepth1 > nDepth2)
82 while (nDepth1 > nDepth2)
87 if (nav1.IsSamePosition (nav2))
88 return XmlNodeOrder.After;
90 else if (nDepth1 < nDepth2)
92 while (nDepth1 < nDepth2)
97 if (nav1.IsSamePosition (nav2))
98 return XmlNodeOrder.Before;
101 XPathNavigator parent1 = nav1.Clone ();
102 XPathNavigator parent2 = nav2.Clone ();
103 while (parent1.MoveToParent () && parent2.MoveToParent ())
105 if (parent1.IsSamePosition (parent2))
107 // the ordering is namespace, attribute, children
108 // assume that nav1 is before nav2, find counter-example
109 if (nav1.NodeType == XPathNodeType.Namespace)
111 if (nav2.NodeType == XPathNodeType.Namespace)
114 while (nav2.MoveToNextNamespace ())
115 if (nav2.IsSamePosition (nav1))
116 return XmlNodeOrder.After;
119 else if (nav1.NodeType == XPathNodeType.Attribute)
121 if (nav2.NodeType == XPathNodeType.Namespace)
122 return XmlNodeOrder.After;
123 else if (nav2.NodeType == XPathNodeType.Attribute)
126 while (nav2.MoveToNextAttribute ())
127 if (nav2.IsSamePosition (nav1))
128 return XmlNodeOrder.After;
133 switch (nav2.NodeType) {
134 case XPathNodeType.Namespace:
135 case XPathNodeType.Attribute:
136 return XmlNodeOrder.After;
139 while (nav2.MoveToNext ())
140 if (nav2.IsSamePosition (nav1))
141 return XmlNodeOrder.After;
143 return XmlNodeOrder.Before;
145 nav1.MoveToParent ();
146 nav2.MoveToParent ();
148 return XmlNodeOrder.Unknown;
151 public virtual XPathExpression Compile (string xpath)
153 XPathParser parser = new XPathParser ();
154 return new CompiledExpression (parser.Compile (xpath));
157 internal virtual XPathExpression Compile (string xpath, System.Xml.Xsl.IStaticXsltContext ctx)
159 XPathParser parser = new XPathParser (ctx);
160 return new CompiledExpression (parser.Compile (xpath));
163 public virtual object Evaluate (string xpath)
165 return Evaluate (Compile (xpath));
168 public virtual object Evaluate (XPathExpression expr)
170 return Evaluate (expr, null);
173 public virtual object Evaluate (XPathExpression expr, XPathNodeIterator context)
175 return Evaluate (expr, context, null);
178 internal virtual object Evaluate (XPathExpression expr, XPathNodeIterator context, XmlNamespaceManager ctx)
180 CompiledExpression cexpr = (CompiledExpression) expr;
182 ctx = cexpr.NamespaceManager;
185 context = new NullIterator (this, ctx);
186 BaseIterator iterContext = (BaseIterator) context;
187 iterContext.NamespaceManager = ctx;
188 return cexpr.Evaluate (iterContext);
191 internal XPathNodeIterator EvaluateNodeSet (XPathExpression expr, XPathNodeIterator context, XmlNamespaceManager ctx)
193 CompiledExpression cexpr = (CompiledExpression) expr;
195 ctx = cexpr.NamespaceManager;
198 context = new NullIterator (this, cexpr.NamespaceManager);
199 BaseIterator iterContext = (BaseIterator) context;
200 iterContext.NamespaceManager = ctx;
201 return cexpr.EvaluateNodeSet (iterContext);
204 internal string EvaluateString (XPathExpression expr, XPathNodeIterator context, XmlNamespaceManager ctx)
206 CompiledExpression cexpr = (CompiledExpression) expr;
208 ctx = cexpr.NamespaceManager;
211 context = new NullIterator (this, cexpr.NamespaceManager);
212 BaseIterator iterContext = (BaseIterator) context;
213 iterContext.NamespaceManager = ctx;
214 return cexpr.EvaluateString (iterContext);
217 internal double EvaluateNumber (XPathExpression expr, XPathNodeIterator context, XmlNamespaceManager ctx)
219 CompiledExpression cexpr = (CompiledExpression) expr;
221 ctx = cexpr.NamespaceManager;
224 context = new NullIterator (this, cexpr.NamespaceManager);
225 BaseIterator iterContext = (BaseIterator) context;
226 iterContext.NamespaceManager = ctx;
227 return cexpr.EvaluateNumber (iterContext);
230 internal bool EvaluateBoolean (XPathExpression expr, XPathNodeIterator context, XmlNamespaceManager ctx)
232 CompiledExpression cexpr = (CompiledExpression) expr;
234 ctx = cexpr.NamespaceManager;
237 context = new NullIterator (this, cexpr.NamespaceManager);
238 BaseIterator iterContext = (BaseIterator) context;
239 iterContext.NamespaceManager = ctx;
240 return cexpr.EvaluateBoolean (iterContext);
243 public abstract string GetAttribute (string localName, string namespaceURI);
245 public abstract string GetNamespace (string name);
247 object ICloneable.Clone ()
252 public virtual bool IsDescendant (XPathNavigator nav)
257 while (nav.MoveToParent ())
259 if (IsSamePosition (nav))
266 public abstract bool IsSamePosition (XPathNavigator other);
268 public virtual bool Matches (string xpath)
270 return Matches (Compile (xpath));
273 [MonoTODO] // optimize...
274 public virtual bool Matches (XPathExpression expr)
276 Expression e = ((CompiledExpression) expr).ExpressionNode;
278 return NodeType == XPathNodeType.Root;
281 return ((NodeTest)e).Match (((CompiledExpression)expr).NamespaceManager, this);
282 if (e is ExprFilter) {
284 e = ((ExprFilter) e).LeftHandSide;
285 } while (e is ExprFilter);
287 if (e is NodeTest && !((NodeTest) e).Match (((CompiledExpression) expr).NamespaceManager, this))
291 XPathResultType resultType = e.ReturnType;
292 switch (resultType) {
293 case XPathResultType.Any:
294 case XPathResultType.NodeSet:
300 switch (e.EvaluatedNodeType) {
301 case XPathNodeType.Attribute:
302 case XPathNodeType.Namespace:
303 if (NodeType != e.EvaluatedNodeType)
308 XPathNodeIterator nodes = Select (expr);
310 while (nodes.MoveNext ()) {
311 if (IsSamePosition (nodes.Current))
315 // ancestors might select this node.
316 if (!e.NeedAbsoluteMatching)
319 XPathNavigator navigator = Clone ();
321 while (navigator.MoveToParent ()) {
322 nodes = navigator.Select (expr);
324 while (nodes.MoveNext ()) {
325 if (IsSamePosition (nodes.Current))
333 public abstract bool MoveTo (XPathNavigator other);
335 public abstract bool MoveToAttribute (string localName, string namespaceURI);
337 public abstract bool MoveToFirst ();
339 public abstract bool MoveToFirstAttribute ();
341 public abstract bool MoveToFirstChild ();
343 public bool MoveToFirstNamespace ()
345 return MoveToFirstNamespace (XPathNamespaceScope.All);
348 public abstract bool MoveToFirstNamespace (XPathNamespaceScope namespaceScope);
350 public abstract bool MoveToId (string id);
352 public abstract bool MoveToNamespace (string name);
354 public abstract bool MoveToNext ();
356 public abstract bool MoveToNextAttribute ();
358 public bool MoveToNextNamespace ()
360 return MoveToNextNamespace (XPathNamespaceScope.All);
363 public abstract bool MoveToNextNamespace (XPathNamespaceScope namespaceScope);
365 public abstract bool MoveToParent ();
367 public abstract bool MoveToPrevious ();
369 public abstract void MoveToRoot ();
371 public virtual XPathNodeIterator Select (string xpath)
373 return Select (Compile (xpath));
376 public virtual XPathNodeIterator Select (XPathExpression expr)
378 return Select (expr, null);
381 internal virtual XPathNodeIterator Select (XPathExpression expr, XmlNamespaceManager ctx)
383 CompiledExpression cexpr = (CompiledExpression) expr;
385 ctx = cexpr.NamespaceManager;
387 BaseIterator iter = new NullIterator (this, ctx);
388 return cexpr.EvaluateNodeSet (iter);
391 public virtual XPathNodeIterator SelectAncestors (XPathNodeType type, bool matchSelf)
393 Axes axis = (matchSelf) ? Axes.AncestorOrSelf : Axes.Ancestor;
394 return SelectTest (new NodeTypeTest (axis, type));
397 public virtual XPathNodeIterator SelectAncestors (string name, string namespaceURI, bool matchSelf)
400 throw new ArgumentNullException ("name");
401 if (namespaceURI == null)
402 throw new ArgumentNullException ("namespaceURI");
404 Axes axis = (matchSelf) ? Axes.AncestorOrSelf : Axes.Ancestor;
405 XmlQualifiedName qname = new XmlQualifiedName (name, namespaceURI);
406 return SelectTest (new NodeNameTest (axis, qname, true));
409 public virtual XPathNodeIterator SelectChildren (XPathNodeType type)
411 return SelectTest (new NodeTypeTest (Axes.Child, type));
414 public virtual XPathNodeIterator SelectChildren (string name, string namespaceURI)
417 throw new ArgumentNullException ("name");
418 if (namespaceURI == null)
419 throw new ArgumentNullException ("namespaceURI");
421 Axes axis = Axes.Child;
422 XmlQualifiedName qname = new XmlQualifiedName (name, namespaceURI);
423 return SelectTest (new NodeNameTest (axis, qname, true));
426 public virtual XPathNodeIterator SelectDescendants (XPathNodeType type, bool matchSelf)
428 Axes axis = (matchSelf) ? Axes.DescendantOrSelf : Axes.Descendant;
429 return SelectTest (new NodeTypeTest (axis, type));
432 public virtual XPathNodeIterator SelectDescendants (string name, string namespaceURI, bool matchSelf)
435 throw new ArgumentNullException ("name");
436 if (namespaceURI == null)
437 throw new ArgumentNullException ("namespaceURI");
440 Axes axis = (matchSelf) ? Axes.DescendantOrSelf : Axes.Descendant;
441 XmlQualifiedName qname = new XmlQualifiedName (name, namespaceURI);
442 return SelectTest (new NodeNameTest (axis, qname, true));
445 internal XPathNodeIterator SelectTest (NodeTest test)
447 return test.EvaluateNodeSet (new NullIterator (this));
450 public override string ToString ()