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;
280 NodeTest nt = e as NodeTest;
282 switch (nt.Axis.Axis) {
287 throw new XPathException ("Only child and attribute pattern are allowed for a pattern.");
289 return nt.Match (((CompiledExpression)expr).NamespaceManager, this);
291 if (e is ExprFilter) {
293 e = ((ExprFilter) e).LeftHandSide;
294 } while (e is ExprFilter);
296 if (e is NodeTest && !((NodeTest) e).Match (((CompiledExpression) expr).NamespaceManager, this))
300 XPathResultType resultType = e.ReturnType;
301 switch (resultType) {
302 case XPathResultType.Any:
303 case XPathResultType.NodeSet:
309 switch (e.EvaluatedNodeType) {
310 case XPathNodeType.Attribute:
311 case XPathNodeType.Namespace:
312 if (NodeType != e.EvaluatedNodeType)
317 XPathNodeIterator nodes;
318 nodes = this.Select (expr);
319 while (nodes.MoveNext ()) {
320 if (IsSamePosition (nodes.Current))
324 // ancestors might select this node.
326 XPathNavigator navigator = Clone ();
328 while (navigator.MoveToParent ()) {
329 nodes = navigator.Select (expr);
331 while (nodes.MoveNext ()) {
332 if (IsSamePosition (nodes.Current))
340 public abstract bool MoveTo (XPathNavigator other);
342 public abstract bool MoveToAttribute (string localName, string namespaceURI);
344 public abstract bool MoveToFirst ();
346 public abstract bool MoveToFirstAttribute ();
348 public abstract bool MoveToFirstChild ();
350 public bool MoveToFirstNamespace ()
352 return MoveToFirstNamespace (XPathNamespaceScope.All);
355 public abstract bool MoveToFirstNamespace (XPathNamespaceScope namespaceScope);
357 public abstract bool MoveToId (string id);
359 public abstract bool MoveToNamespace (string name);
361 public abstract bool MoveToNext ();
363 public abstract bool MoveToNextAttribute ();
365 public bool MoveToNextNamespace ()
367 return MoveToNextNamespace (XPathNamespaceScope.All);
370 public abstract bool MoveToNextNamespace (XPathNamespaceScope namespaceScope);
372 public abstract bool MoveToParent ();
374 public abstract bool MoveToPrevious ();
376 public abstract void MoveToRoot ();
378 public virtual XPathNodeIterator Select (string xpath)
380 return Select (Compile (xpath));
383 public virtual XPathNodeIterator Select (XPathExpression expr)
385 return Select (expr, null);
388 internal virtual XPathNodeIterator Select (XPathExpression expr, XmlNamespaceManager ctx)
390 CompiledExpression cexpr = (CompiledExpression) expr;
392 ctx = cexpr.NamespaceManager;
394 BaseIterator iter = new NullIterator (this, ctx);
395 return cexpr.EvaluateNodeSet (iter);
398 public virtual XPathNodeIterator SelectAncestors (XPathNodeType type, bool matchSelf)
400 Axes axis = (matchSelf) ? Axes.AncestorOrSelf : Axes.Ancestor;
401 return SelectTest (new NodeTypeTest (axis, type));
404 public virtual XPathNodeIterator SelectAncestors (string name, string namespaceURI, bool matchSelf)
407 throw new ArgumentNullException ("name");
408 if (namespaceURI == null)
409 throw new ArgumentNullException ("namespaceURI");
411 Axes axis = (matchSelf) ? Axes.AncestorOrSelf : Axes.Ancestor;
412 XmlQualifiedName qname = new XmlQualifiedName (name, namespaceURI);
413 return SelectTest (new NodeNameTest (axis, qname, true));
416 public virtual XPathNodeIterator SelectChildren (XPathNodeType type)
418 return SelectTest (new NodeTypeTest (Axes.Child, type));
421 public virtual XPathNodeIterator SelectChildren (string name, string namespaceURI)
424 throw new ArgumentNullException ("name");
425 if (namespaceURI == null)
426 throw new ArgumentNullException ("namespaceURI");
428 Axes axis = Axes.Child;
429 XmlQualifiedName qname = new XmlQualifiedName (name, namespaceURI);
430 return SelectTest (new NodeNameTest (axis, qname, true));
433 public virtual XPathNodeIterator SelectDescendants (XPathNodeType type, bool matchSelf)
435 Axes axis = (matchSelf) ? Axes.DescendantOrSelf : Axes.Descendant;
436 return SelectTest (new NodeTypeTest (axis, type));
439 public virtual XPathNodeIterator SelectDescendants (string name, string namespaceURI, bool matchSelf)
442 throw new ArgumentNullException ("name");
443 if (namespaceURI == null)
444 throw new ArgumentNullException ("namespaceURI");
447 Axes axis = (matchSelf) ? Axes.DescendantOrSelf : Axes.Descendant;
448 XmlQualifiedName qname = new XmlQualifiedName (name, namespaceURI);
449 return SelectTest (new NodeNameTest (axis, qname, true));
452 internal XPathNodeIterator SelectTest (NodeTest test)
454 return test.EvaluateNodeSet (new NullIterator (this));
457 public override string ToString ()