2003-11-24 Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
[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                         
278                         if (e is NodeTest)
279                                 return ((NodeTest)e).Match (((CompiledExpression)expr).NamespaceManager, this);
280                         if (e is ExprFilter) {
281                                 do {
282                                         e = ((ExprFilter)e).LeftHandSide;
283                                 } while (e is ExprFilter);
284                                 
285                                 if (e is NodeTest && !((NodeTest)e).Match (((CompiledExpression)expr).NamespaceManager, this))
286                                         return false;
287                         }
288                         
289                         //e = ((CompiledExpression)expr).ExpressionNode;
290                         //Console.WriteLine ("Didnt filter : " + e.GetType ().ToString () + " " + e.ToString ());
291                         
292                         XPathNodeIterator nodes = Select (expr);
293
294                         while (nodes.MoveNext ()) {
295                                 if (IsSamePosition (nodes.Current))
296                                         return true;
297                         }
298
299                         XPathNavigator navigator = Clone ();
300
301                         while (navigator.MoveToParent ()) {
302                                 nodes = navigator.Select (expr);
303
304                                 while (nodes.MoveNext ()) {
305                                         if (IsSamePosition (nodes.Current))
306                                                 return true;
307                                 }
308                         }
309
310                         return false;
311                 }
312
313                 public abstract bool MoveTo (XPathNavigator other);
314
315                 public abstract bool MoveToAttribute (string localName, string namespaceURI);
316
317                 public abstract bool MoveToFirst ();
318
319                 public abstract bool MoveToFirstAttribute ();
320
321                 public abstract bool MoveToFirstChild ();
322
323                 public bool MoveToFirstNamespace ()
324                 {
325                         return MoveToFirstNamespace (XPathNamespaceScope.All);
326                 }
327
328                 public abstract bool MoveToFirstNamespace (XPathNamespaceScope namespaceScope);
329
330                 public abstract bool MoveToId (string id);
331
332                 public abstract bool MoveToNamespace (string name);
333
334                 public abstract bool MoveToNext ();
335
336                 public abstract bool MoveToNextAttribute ();
337
338                 public bool MoveToNextNamespace ()
339                 {
340                         return MoveToNextNamespace (XPathNamespaceScope.All);
341                 }
342
343                 public abstract bool MoveToNextNamespace (XPathNamespaceScope namespaceScope);
344
345                 public abstract bool MoveToParent ();
346
347                 public abstract bool MoveToPrevious ();
348
349                 public abstract void MoveToRoot ();
350
351                 public virtual XPathNodeIterator Select (string xpath)
352                 {
353                         return Select (Compile (xpath));
354                 }
355
356                 public virtual XPathNodeIterator Select (XPathExpression expr)
357                 {
358                         return Select (expr, null);
359                 }
360                 
361                 internal virtual XPathNodeIterator Select (XPathExpression expr, XmlNamespaceManager ctx)
362                 {
363                         CompiledExpression cexpr = (CompiledExpression) expr;
364                         if (ctx == null)
365                                 ctx = cexpr.NamespaceManager;
366                         
367                         BaseIterator iter = new NullIterator (this, ctx);
368                         return cexpr.EvaluateNodeSet (iter);    
369                 }
370
371                 public virtual XPathNodeIterator SelectAncestors (XPathNodeType type, bool matchSelf)
372                 {
373                         Axes axis = (matchSelf) ? Axes.AncestorOrSelf : Axes.Ancestor;
374                         return SelectTest (new NodeTypeTest (axis, type));
375                 }
376
377                 public virtual XPathNodeIterator SelectAncestors (string name, string namespaceURI, bool matchSelf)
378                 {
379                         if (name == null)
380                                 throw new ArgumentNullException ("name");
381                         if (namespaceURI == null)
382                                 throw new ArgumentNullException ("namespaceURI");
383
384                         Axes axis = (matchSelf) ? Axes.AncestorOrSelf : Axes.Ancestor;
385                         XmlQualifiedName qname = new XmlQualifiedName (name, namespaceURI);
386                         return SelectTest (new NodeNameTest (axis, qname, true));
387                 }
388
389                 public virtual XPathNodeIterator SelectChildren (XPathNodeType type)
390                 {
391                         return SelectTest (new NodeTypeTest (Axes.Child, type));
392                 }
393
394                 public virtual XPathNodeIterator SelectChildren (string name, string namespaceURI)
395                 {
396                         if (name == null)
397                                 throw new ArgumentNullException ("name");
398                         if (namespaceURI == null)
399                                 throw new ArgumentNullException ("namespaceURI");
400
401                         Axes axis = Axes.Child;
402                         XmlQualifiedName qname = new XmlQualifiedName (name, namespaceURI);
403                         return SelectTest (new NodeNameTest (axis, qname, true));
404                 }
405
406                 public virtual XPathNodeIterator SelectDescendants (XPathNodeType type, bool matchSelf)
407                 {
408                         Axes axis = (matchSelf) ? Axes.DescendantOrSelf : Axes.Descendant;
409                         return SelectTest (new NodeTypeTest (axis, type));
410                 }
411
412                 public virtual XPathNodeIterator SelectDescendants (string name, string namespaceURI, bool matchSelf)
413                 {
414                         if (name == null)
415                                 throw new ArgumentNullException ("name");
416                         if (namespaceURI == null)
417                                 throw new ArgumentNullException ("namespaceURI");
418
419
420                         Axes axis = (matchSelf) ? Axes.DescendantOrSelf : Axes.Descendant;
421                         XmlQualifiedName qname = new XmlQualifiedName (name, namespaceURI);
422                         return SelectTest (new NodeNameTest (axis, qname, true));
423                 }
424
425                 internal XPathNodeIterator SelectTest (NodeTest test)
426                 {
427                         return test.EvaluateNodeSet (new NullIterator (this));
428                 }
429
430                 public override string ToString ()
431                 {
432                         return Value;
433                 }
434
435                 #endregion
436         }
437 }