c7b14ff4b1dec584eb7a21d93f1ed77531bea0bf
[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                 [MonoTODO]
70                 public virtual XmlNodeOrder ComparePosition (XPathNavigator nav)
71                 {
72                         if (IsSamePosition (nav))
73                                 return XmlNodeOrder.Same;
74
75                         XPathNavigator nav1 = Clone ();
76                         XPathNavigator nav2 = nav.Clone ();
77
78                         int nDepth1 = nav1.Depth;
79                         int nDepth2 = nav2.Depth;
80
81                         if (nDepth1 > nDepth2)
82                         {
83                                 while (nDepth1 > nDepth2)
84                                 {
85                                         nav1.MoveToParent ();
86                                         nDepth1 --;
87                                 }
88                                 if (nav1.IsSamePosition (nav2))
89                                         return XmlNodeOrder.After;
90                         }
91                         else if (nDepth1 < nDepth2)
92                         {
93                                 while (nDepth1 < nDepth2)
94                                 {
95                                         nav2.MoveToParent ();
96                                         nDepth2 --;
97                                 }
98                                 if (nav1.IsSamePosition (nav2))
99                                         return XmlNodeOrder.Before;
100                         }
101
102                         XPathNavigator parent1 = nav1.Clone ();
103                         XPathNavigator parent2 = nav2.Clone ();
104                         while (parent1.MoveToParent () && parent2.MoveToParent ())
105                         {
106                                 if (parent1.IsSamePosition (parent2))
107                                 {
108                                         // the ordering is namespace, attribute, children
109                                         // assume that nav1 is before nav2, find counter-example
110                                         if (nav1.NodeType == XPathNodeType.Namespace)
111                                         {
112                                                 if (nav2.NodeType == XPathNodeType.Namespace)
113                                                 {
114                                                         // match namespaces
115                                                         while (nav2.MoveToNextNamespace ())
116                                                                 if (nav2.IsSamePosition (nav1))
117                                                                         return XmlNodeOrder.After;
118                                                 }
119                                         }
120                                         else if (nav1.NodeType == XPathNodeType.Attribute)
121                                         {
122                                                 if (nav2.NodeType == XPathNodeType.Namespace)
123                                                         return XmlNodeOrder.After;
124                                                 else if (nav2.NodeType == XPathNodeType.Attribute)
125                                                 {
126                                                         // match attributes
127                                                         while (nav2.MoveToNextAttribute ())
128                                                                 if (nav2.IsSamePosition (nav1))
129                                                                         return XmlNodeOrder.After;
130                                                 }
131                                         }
132                                         else
133                                         {
134                                                 // match children
135                                                 while (nav2.MoveToNext ())
136                                                         if (nav2.IsSamePosition (nav1))
137                                                                 return XmlNodeOrder.After;
138                                         }
139                                         return XmlNodeOrder.Before;
140                                 }
141                                 nav1.MoveToParent ();
142                                 nav2.MoveToParent ();
143                         }
144                         return XmlNodeOrder.Unknown;
145                 }
146
147                 public virtual XPathExpression Compile (string xpath)
148                 {
149                         Tokenizer tokenizer = new Tokenizer (xpath);
150                         XPathParser parser = new XPathParser ();
151                         Expression expr = (Expression) parser.yyparseSafe (tokenizer);
152 //                      Expression expr = (Expression) parser.yyparseDebug (tokenizer);
153                         return new CompiledExpression (expr);
154                 }
155
156                 public virtual object Evaluate (string xpath)
157                 {
158                         return Evaluate (Compile (xpath));
159                 }
160
161                 public virtual object Evaluate (XPathExpression expr)
162                 {
163                         return Evaluate (expr, null);
164                 }
165
166                 public virtual object Evaluate (XPathExpression expr, XPathNodeIterator context)
167                 {
168                         CompiledExpression cexpr = (CompiledExpression) expr;
169                         if (context == null)
170                                 context = new NullIterator (this, cexpr.NamespaceManager);
171                         BaseIterator iterContext = (BaseIterator) context;
172                         iterContext.NamespaceManager = cexpr.NamespaceManager;
173                         return cexpr.Evaluate (iterContext);
174                 }
175
176                 internal XPathNodeIterator EvaluateNodeSet (XPathExpression expr, XPathNodeIterator context)
177                 {
178                         CompiledExpression cexpr = (CompiledExpression) expr;
179                         if (context == null)
180                                 context = new NullIterator (this, cexpr.NamespaceManager);
181                         BaseIterator iterContext = (BaseIterator) context;
182                         iterContext.NamespaceManager = cexpr.NamespaceManager;
183                         return cexpr.EvaluateNodeSet (iterContext);
184                 }
185
186                 internal string EvaluateString (XPathExpression expr, XPathNodeIterator context)
187                 {
188                         CompiledExpression cexpr = (CompiledExpression) expr;
189                         if (context == null)
190                                 context = new NullIterator (this, cexpr.NamespaceManager);
191                         BaseIterator iterContext = (BaseIterator) context;
192                         iterContext.NamespaceManager = cexpr.NamespaceManager;
193                         return cexpr.EvaluateString (iterContext);
194                 }
195
196                 internal double EvaluateNumber (XPathExpression expr, XPathNodeIterator context)
197                 {
198                         CompiledExpression cexpr = (CompiledExpression) expr;
199                         if (context == null)
200                                 context = new NullIterator (this, cexpr.NamespaceManager);
201                         BaseIterator iterContext = (BaseIterator) context;
202                         iterContext.NamespaceManager = cexpr.NamespaceManager;
203                         return cexpr.EvaluateNumber (iterContext);
204                 }
205
206                 internal bool EvaluateBoolean (XPathExpression expr, XPathNodeIterator context)
207                 {
208                         CompiledExpression cexpr = (CompiledExpression) expr;
209                         if (context == null)
210                                 context = new NullIterator (this, cexpr.NamespaceManager);
211                         BaseIterator iterContext = (BaseIterator) context;
212                         iterContext.NamespaceManager = cexpr.NamespaceManager;
213                         return cexpr.EvaluateBoolean (iterContext);
214                 }
215
216                 public abstract string GetAttribute (string localName, string namespaceURI);
217
218                 public abstract string GetNamespace (string name);
219                 
220                 object ICloneable.Clone ()
221                 {
222                         return Clone ();
223                 }
224
225                 public virtual bool IsDescendant (XPathNavigator nav)
226                 {
227                         if (nav != null)
228                         {
229                                 nav = nav.Clone ();
230                                 while (nav.MoveToParent ())
231                                 {
232                                         if (IsSamePosition (nav))
233                                                 return true;
234                                 }
235                         }
236                         return false;
237                 }
238
239                 public abstract bool IsSamePosition (XPathNavigator other);
240
241                 public virtual bool Matches (string xpath)
242                 {
243                         return Matches (Compile (xpath));
244                 }
245
246                 public virtual bool Matches (XPathExpression expr)
247                 {
248                         XPathNodeIterator nodes = Select (expr);
249
250                         while (nodes.MoveNext ()) {
251                                 if (IsSamePosition (nodes.Current))
252                                         return true;
253                         }
254
255                         XPathNavigator navigator = Clone ();
256
257                         while (navigator.MoveToParent ()) {
258                                 nodes = navigator.Select (expr);
259
260                                 while (nodes.MoveNext ()) {
261                                         if (IsSamePosition (nodes.Current))
262                                                 return true;
263                                 }
264                         }
265
266                         return false;
267                 }
268
269                 public abstract bool MoveTo (XPathNavigator other);
270
271                 public abstract bool MoveToAttribute (string localName, string namespaceURI);
272
273                 public abstract bool MoveToFirst ();
274
275                 public abstract bool MoveToFirstAttribute ();
276
277                 public abstract bool MoveToFirstChild ();
278
279                 public bool MoveToFirstNamespace ()
280                 {
281                         return MoveToFirstNamespace (XPathNamespaceScope.All);
282                 }
283
284                 public abstract bool MoveToFirstNamespace (XPathNamespaceScope namespaceScope);
285
286                 public abstract bool MoveToId (string id);
287
288                 public abstract bool MoveToNamespace (string name);
289
290                 public abstract bool MoveToNext ();
291
292                 public abstract bool MoveToNextAttribute ();
293
294                 public bool MoveToNextNamespace ()
295                 {
296                         return MoveToNextNamespace (XPathNamespaceScope.All);
297                 }
298
299                 public abstract bool MoveToNextNamespace (XPathNamespaceScope namespaceScope);
300
301                 public abstract bool MoveToParent ();
302
303                 public abstract bool MoveToPrevious ();
304
305                 public abstract void MoveToRoot ();
306
307                 public virtual XPathNodeIterator Select (string xpath)
308                 {
309                         return Select (Compile (xpath));
310                 }
311
312                 public virtual XPathNodeIterator Select (XPathExpression expr)
313                 {
314                         CompiledExpression cexpr = (CompiledExpression) expr;
315                         BaseIterator iter = new NullIterator (this, cexpr.NamespaceManager);
316                         return cexpr.EvaluateNodeSet (iter);
317                 }
318
319                 public virtual XPathNodeIterator SelectAncestors (XPathNodeType type, bool matchSelf)
320                 {
321                         Axes axis = (matchSelf) ? Axes.AncestorOrSelf : Axes.Ancestor;
322                         NodeTest test = new NodeTypeTest (axis, type);
323                         return SelectTest (test);
324                 }
325
326                 [MonoTODO]
327                 public virtual XPathNodeIterator SelectAncestors (string name, string namespaceURI, bool matchSelf)
328                 {
329                         if (namespaceURI != null && namespaceURI != "")
330                                 throw new NotImplementedException ();
331
332                         Axes axis = (matchSelf) ? Axes.AncestorOrSelf : Axes.Ancestor;
333                         XmlQualifiedName qname = new XmlQualifiedName (name);
334                         NodeTest test = new NodeNameTest (axis, qname);
335                         return SelectTest (test);
336                 }
337
338                 public virtual XPathNodeIterator SelectChildren (XPathNodeType type)
339                 {
340                         NodeTest test = new NodeTypeTest (Axes.Child, type);
341                         return SelectTest (test);
342                 }
343
344                 [MonoTODO]
345                 public virtual XPathNodeIterator SelectChildren (string name, string namespaceURI)
346                 {
347                         if (namespaceURI != null && namespaceURI != "")
348                                 throw new NotImplementedException ();
349
350                         Axes axis = Axes.Child;
351                         XmlQualifiedName qname = new XmlQualifiedName (name);
352                         NodeTest test = new NodeNameTest (axis, qname);
353                         return SelectTest (test);
354                 }
355
356                 public virtual XPathNodeIterator SelectDescendants (XPathNodeType type, bool matchSelf)
357                 {
358                         Axes axis = (matchSelf) ? Axes.DescendantOrSelf : Axes.Descendant;
359                         NodeTest test = new NodeTypeTest (axis, type);
360                         return SelectTest (test);
361                 }
362
363                 [MonoTODO]
364                 public virtual XPathNodeIterator SelectDescendants (string name, string namespaceURI, bool matchSelf)
365                 {
366                         if (namespaceURI != null && namespaceURI != "")
367                                 throw new NotImplementedException ();
368
369                         Axes axis = (matchSelf) ? Axes.DescendantOrSelf : Axes.Descendant;
370                         XmlQualifiedName qname = new XmlQualifiedName (name);
371                         NodeTest test = new NodeNameTest (axis, qname);
372                         return SelectTest (test);
373                 }
374
375                 internal XPathNodeIterator SelectTest (NodeTest test)
376                 {
377                         Expression expr = new ExprStep (test, null);
378                         BaseIterator iter = new NullIterator (this, null);
379                         return expr.EvaluateNodeSet (iter);
380                 }
381
382                 public override string ToString ()
383                 {
384                         return Value;
385                 }
386
387                 #endregion
388         }
389 }