2004-02-16 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.XML / System.Xml.XPath / XPathNavigator.cs
1 //
2 // System.Xml.XPath.XPathNavigator
3 //
4 // Author:
5 //   Jason Diamond (jason@injektilo.org)
6 //
7 // (C) 2002 Jason Diamond  http://injektilo.org/
8 //
9
10 using System;
11 using Mono.Xml.XPath;
12
13 namespace System.Xml.XPath
14 {
15         public abstract class XPathNavigator : ICloneable
16         {
17                 #region Constructor
18
19                 protected XPathNavigator ()
20                 {
21                 }
22
23                 #endregion
24
25                 #region Properties
26
27                 public abstract string BaseURI { get; }
28
29                 public abstract bool HasAttributes { get; }
30
31                 public abstract bool HasChildren { get; }
32
33                 public abstract bool IsEmptyElement { get; }
34
35                 public abstract string LocalName { get; }
36
37                 public abstract string Name { get; }
38
39                 public abstract string NamespaceURI { get; }
40
41                 public abstract XmlNameTable NameTable { get; }
42
43                 public abstract XPathNodeType NodeType { get; }
44
45                 public abstract string Prefix { get; }
46
47                 public abstract string Value { get; }
48
49                 public abstract string XmlLang { get; }
50
51                 int Depth
52                 {
53                         get
54                         {
55                                 int cLevels = 0;
56                                 XPathNavigator nav = Clone ();
57                                 while (nav.MoveToParent ())
58                                         cLevels ++;
59                                 return cLevels;
60                         }
61                 }
62
63                 #endregion
64
65                 #region Methods
66
67                 public abstract XPathNavigator Clone ();
68
69                 public virtual XmlNodeOrder ComparePosition (XPathNavigator nav)
70                 {
71                         if (IsSamePosition (nav))
72                                 return XmlNodeOrder.Same;
73
74                         XPathNavigator nav1 = Clone ();
75                         XPathNavigator nav2 = nav.Clone ();
76
77                         int nDepth1 = nav1.Depth;
78                         int nDepth2 = nav2.Depth;
79
80                         if (nDepth1 > nDepth2)
81                         {
82                                 while (nDepth1 > nDepth2)
83                                 {
84                                         nav1.MoveToParent ();
85                                         nDepth1 --;
86                                 }
87                                 if (nav1.IsSamePosition (nav2))
88                                         return XmlNodeOrder.After;
89                         }
90                         else if (nDepth1 < nDepth2)
91                         {
92                                 while (nDepth1 < nDepth2)
93                                 {
94                                         nav2.MoveToParent ();
95                                         nDepth2 --;
96                                 }
97                                 if (nav1.IsSamePosition (nav2))
98                                         return XmlNodeOrder.Before;
99                         }
100
101                         XPathNavigator parent1 = nav1.Clone ();
102                         XPathNavigator parent2 = nav2.Clone ();
103                         while (parent1.MoveToParent () && parent2.MoveToParent ())
104                         {
105                                 if (parent1.IsSamePosition (parent2))
106                                 {
107                                         // the ordering is namespace, attribute, children
108                                         // assume that nav1 is before nav2, find counter-example
109                                         if (nav1.NodeType == XPathNodeType.Namespace)
110                                         {
111                                                 if (nav2.NodeType == XPathNodeType.Namespace)
112                                                 {
113                                                         // match namespaces
114                                                         while (nav2.MoveToNextNamespace ())
115                                                                 if (nav2.IsSamePosition (nav1))
116                                                                         return XmlNodeOrder.After;
117                                                 }
118                                         }
119                                         else if (nav1.NodeType == XPathNodeType.Attribute)
120                                         {
121                                                 if (nav2.NodeType == XPathNodeType.Namespace)
122                                                         return XmlNodeOrder.After;
123                                                 else if (nav2.NodeType == XPathNodeType.Attribute)
124                                                 {
125                                                         // match attributes
126                                                         while (nav2.MoveToNextAttribute ())
127                                                                 if (nav2.IsSamePosition (nav1))
128                                                                         return XmlNodeOrder.After;
129                                                 }
130                                         }
131                                         else
132                                         {
133                                                 switch (nav2.NodeType) {
134                                                 case XPathNodeType.Namespace:
135                                                 case XPathNodeType.Attribute:
136                                                         return XmlNodeOrder.After;
137                                                 }
138                                                 // match children
139                                                 while (nav2.MoveToNext ())
140                                                         if (nav2.IsSamePosition (nav1))
141                                                                 return XmlNodeOrder.After;
142                                         }
143                                         return XmlNodeOrder.Before;
144                                 }
145                                 nav1.MoveToParent ();
146                                 nav2.MoveToParent ();
147                         }
148                         return XmlNodeOrder.Unknown;
149                 }
150
151                 public virtual XPathExpression Compile (string xpath)
152                 {
153                         XPathParser parser = new XPathParser ();
154                         return new CompiledExpression (parser.Compile (xpath));
155                 }
156                 
157                 internal virtual XPathExpression Compile (string xpath, System.Xml.Xsl.IStaticXsltContext ctx)
158                 {
159                         XPathParser parser = new XPathParser (ctx);
160                         return new CompiledExpression (parser.Compile (xpath));
161                 }
162
163                 public virtual object Evaluate (string xpath)
164                 {
165                         return Evaluate (Compile (xpath));
166                 }
167
168                 public virtual object Evaluate (XPathExpression expr)
169                 {
170                         return Evaluate (expr, null);
171                 }
172
173                 public virtual object Evaluate (XPathExpression expr, XPathNodeIterator context)
174                 {
175                         return Evaluate (expr, context, null);
176                 }
177                 
178                 internal virtual object Evaluate (XPathExpression expr, XPathNodeIterator context, XmlNamespaceManager ctx)
179                 {
180                         CompiledExpression cexpr = (CompiledExpression) expr;
181                         if (ctx == null)
182                                 ctx = cexpr.NamespaceManager;
183                         
184                         if (context == null)
185                                 context = new NullIterator (this, ctx);
186                         BaseIterator iterContext = (BaseIterator) context;
187                         iterContext.NamespaceManager = ctx;
188                         return cexpr.Evaluate (iterContext);
189                 }
190
191                 internal XPathNodeIterator EvaluateNodeSet (XPathExpression expr, XPathNodeIterator context, XmlNamespaceManager ctx)
192                 {
193                         CompiledExpression cexpr = (CompiledExpression) expr;
194                         if (ctx == null)
195                                 ctx = cexpr.NamespaceManager;
196                         
197                         if (context == null)
198                                 context = new NullIterator (this, cexpr.NamespaceManager);
199                         BaseIterator iterContext = (BaseIterator) context;
200                         iterContext.NamespaceManager = ctx;
201                         return cexpr.EvaluateNodeSet (iterContext);
202                 }
203
204                 internal string EvaluateString (XPathExpression expr, XPathNodeIterator context, XmlNamespaceManager ctx)
205                 {
206                         CompiledExpression cexpr = (CompiledExpression) expr;
207                         if (ctx == null)
208                                 ctx = cexpr.NamespaceManager;
209                         
210                         if (context == null)
211                                 context = new NullIterator (this, cexpr.NamespaceManager);
212                         BaseIterator iterContext = (BaseIterator) context;
213                         iterContext.NamespaceManager = ctx;
214                         return cexpr.EvaluateString (iterContext);
215                 }
216
217                 internal double EvaluateNumber (XPathExpression expr, XPathNodeIterator context, XmlNamespaceManager ctx)
218                 {
219                         CompiledExpression cexpr = (CompiledExpression) expr;
220                         if (ctx == null)
221                                 ctx = cexpr.NamespaceManager;
222                         
223                         if (context == null)
224                                 context = new NullIterator (this, cexpr.NamespaceManager);
225                         BaseIterator iterContext = (BaseIterator) context;
226                         iterContext.NamespaceManager = ctx;
227                         return cexpr.EvaluateNumber (iterContext);
228                 }
229
230                 internal bool EvaluateBoolean (XPathExpression expr, XPathNodeIterator context, XmlNamespaceManager ctx)
231                 {
232                         CompiledExpression cexpr = (CompiledExpression) expr;
233                         if (ctx == null)
234                                 ctx = cexpr.NamespaceManager;
235                         
236                         if (context == null)
237                                 context = new NullIterator (this, cexpr.NamespaceManager);
238                         BaseIterator iterContext = (BaseIterator) context;
239                         iterContext.NamespaceManager = ctx;
240                         return cexpr.EvaluateBoolean (iterContext);
241                 }
242
243                 public abstract string GetAttribute (string localName, string namespaceURI);
244
245                 public abstract string GetNamespace (string name);
246                 
247                 object ICloneable.Clone ()
248                 {
249                         return Clone ();
250                 }
251
252                 public virtual bool IsDescendant (XPathNavigator nav)
253                 {
254                         if (nav != null)
255                         {
256                                 nav = nav.Clone ();
257                                 while (nav.MoveToParent ())
258                                 {
259                                         if (IsSamePosition (nav))
260                                                 return true;
261                                 }
262                         }
263                         return false;
264                 }
265
266                 public abstract bool IsSamePosition (XPathNavigator other);
267
268                 public virtual bool Matches (string xpath)
269                 {
270                         return Matches (Compile (xpath));
271                 }
272
273                 [MonoTODO]      // optimize...
274                 public virtual bool Matches (XPathExpression expr)
275                 {
276                         Expression e = ((CompiledExpression) expr).ExpressionNode;
277                         if (e is ExprRoot)
278                                 return NodeType == XPathNodeType.Root;
279                         
280                         if (e is NodeTest)
281                                 return ((NodeTest)e).Match (((CompiledExpression)expr).NamespaceManager, this);
282                         if (e is ExprFilter) {
283                                 do {
284                                         e = ((ExprFilter) e).LeftHandSide;
285                                 } while (e is ExprFilter);
286                                 
287                                 if (e is NodeTest && !((NodeTest) e).Match (((CompiledExpression) expr).NamespaceManager, this))
288                                         return false;
289                         }
290
291                         XPathResultType resultType = e.ReturnType;
292                         switch (resultType) {
293                         case XPathResultType.Any:
294                         case XPathResultType.NodeSet:
295                                 break;
296                         default:
297                                 return false;
298                         }
299
300                         switch (e.EvaluatedNodeType) {
301                         case XPathNodeType.Attribute:
302                         case XPathNodeType.Namespace:
303                                 if (NodeType != e.EvaluatedNodeType)
304                                         return false;
305                                 break;
306                         }
307
308                         XPathNodeIterator nodes = Select (expr);
309
310                         while (nodes.MoveNext ()) {
311                                 if (IsSamePosition (nodes.Current))
312                                         return true;
313                         }
314
315                         // ancestors might select this node.
316 //                      if (!e.NeedAbsoluteMatching)
317 //                              return false;
318
319                         XPathNavigator navigator = Clone ();
320
321                         while (navigator.MoveToParent ()) {
322                                 nodes = navigator.Select (expr);
323
324                                 while (nodes.MoveNext ()) {
325                                         if (IsSamePosition (nodes.Current))
326                                                 return true;
327                                 }
328                         }
329
330                         return false;
331                 }
332
333                 public abstract bool MoveTo (XPathNavigator other);
334
335                 public abstract bool MoveToAttribute (string localName, string namespaceURI);
336
337                 public abstract bool MoveToFirst ();
338
339                 public abstract bool MoveToFirstAttribute ();
340
341                 public abstract bool MoveToFirstChild ();
342
343                 public bool MoveToFirstNamespace ()
344                 {
345                         return MoveToFirstNamespace (XPathNamespaceScope.All);
346                 }
347
348                 public abstract bool MoveToFirstNamespace (XPathNamespaceScope namespaceScope);
349
350                 public abstract bool MoveToId (string id);
351
352                 public abstract bool MoveToNamespace (string name);
353
354                 public abstract bool MoveToNext ();
355
356                 public abstract bool MoveToNextAttribute ();
357
358                 public bool MoveToNextNamespace ()
359                 {
360                         return MoveToNextNamespace (XPathNamespaceScope.All);
361                 }
362
363                 public abstract bool MoveToNextNamespace (XPathNamespaceScope namespaceScope);
364
365                 public abstract bool MoveToParent ();
366
367                 public abstract bool MoveToPrevious ();
368
369                 public abstract void MoveToRoot ();
370
371                 public virtual XPathNodeIterator Select (string xpath)
372                 {
373                         return Select (Compile (xpath));
374                 }
375
376                 public virtual XPathNodeIterator Select (XPathExpression expr)
377                 {
378                         return Select (expr, null);
379                 }
380                 
381                 internal virtual XPathNodeIterator Select (XPathExpression expr, XmlNamespaceManager ctx)
382                 {
383                         CompiledExpression cexpr = (CompiledExpression) expr;
384                         if (ctx == null)
385                                 ctx = cexpr.NamespaceManager;
386                         
387                         BaseIterator iter = new NullIterator (this, ctx);
388                         return cexpr.EvaluateNodeSet (iter);    
389                 }
390
391                 public virtual XPathNodeIterator SelectAncestors (XPathNodeType type, bool matchSelf)
392                 {
393                         Axes axis = (matchSelf) ? Axes.AncestorOrSelf : Axes.Ancestor;
394                         return SelectTest (new NodeTypeTest (axis, type));
395                 }
396
397                 public virtual XPathNodeIterator SelectAncestors (string name, string namespaceURI, bool matchSelf)
398                 {
399                         if (name == null)
400                                 throw new ArgumentNullException ("name");
401                         if (namespaceURI == null)
402                                 throw new ArgumentNullException ("namespaceURI");
403
404                         Axes axis = (matchSelf) ? Axes.AncestorOrSelf : Axes.Ancestor;
405                         XmlQualifiedName qname = new XmlQualifiedName (name, namespaceURI);
406                         return SelectTest (new NodeNameTest (axis, qname, true));
407                 }
408
409                 public virtual XPathNodeIterator SelectChildren (XPathNodeType type)
410                 {
411                         return SelectTest (new NodeTypeTest (Axes.Child, type));
412                 }
413
414                 public virtual XPathNodeIterator SelectChildren (string name, string namespaceURI)
415                 {
416                         if (name == null)
417                                 throw new ArgumentNullException ("name");
418                         if (namespaceURI == null)
419                                 throw new ArgumentNullException ("namespaceURI");
420
421                         Axes axis = Axes.Child;
422                         XmlQualifiedName qname = new XmlQualifiedName (name, namespaceURI);
423                         return SelectTest (new NodeNameTest (axis, qname, true));
424                 }
425
426                 public virtual XPathNodeIterator SelectDescendants (XPathNodeType type, bool matchSelf)
427                 {
428                         Axes axis = (matchSelf) ? Axes.DescendantOrSelf : Axes.Descendant;
429                         return SelectTest (new NodeTypeTest (axis, type));
430                 }
431
432                 public virtual XPathNodeIterator SelectDescendants (string name, string namespaceURI, bool matchSelf)
433                 {
434                         if (name == null)
435                                 throw new ArgumentNullException ("name");
436                         if (namespaceURI == null)
437                                 throw new ArgumentNullException ("namespaceURI");
438
439
440                         Axes axis = (matchSelf) ? Axes.DescendantOrSelf : Axes.Descendant;
441                         XmlQualifiedName qname = new XmlQualifiedName (name, namespaceURI);
442                         return SelectTest (new NodeNameTest (axis, qname, true));
443                 }
444
445                 internal XPathNodeIterator SelectTest (NodeTest test)
446                 {
447                         return test.EvaluateNodeSet (new NullIterator (this));
448                 }
449
450                 public override string ToString ()
451                 {
452                         return Value;
453                 }
454
455                 #endregion
456         }
457 }