2004-07-11 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 //   Atsushi Enomoto (atsushi@ximian.com)
7 //
8 // (C) 2002 Jason Diamond  http://injektilo.org/
9 // (C) 2004 Novell Inc.
10 //
11
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System;
34 using System.Collections;
35 using System.Xml;
36 using System.Xml.Schema;
37 using Mono.Xml.XPath;
38
39 #if NET_2_0
40 using NSResolver = System.Xml.IXmlNamespaceResolver;
41 #else
42 using NSResolver = System.Xml.XmlNamespaceManager;
43 #endif
44
45 namespace System.Xml.XPath
46 {
47 #if NET_2_0
48         public abstract class XPathNavigator : XPathItem,
49                 ICloneable, IXPathNavigable, IXmlNamespaceResolver
50 #else
51         public abstract class XPathNavigator : ICloneable
52 #endif
53         {
54                 #region Constructor
55
56                 protected XPathNavigator ()
57                 {
58                 }
59
60                 #endregion
61
62                 #region Properties
63
64                 public abstract string BaseURI { get; }
65
66                 public abstract bool HasAttributes { get; }
67
68                 public abstract bool HasChildren { get; }
69
70                 public abstract bool IsEmptyElement { get; }
71
72                 public abstract string LocalName { get; }
73
74                 public abstract string Name { get; }
75
76                 public abstract string NamespaceURI { get; }
77
78                 public abstract XmlNameTable NameTable { get; }
79
80                 public abstract XPathNodeType NodeType { get; }
81
82                 public abstract string Prefix { get; }
83
84 #if NET_2_0
85 #else
86                 public abstract string Value { get; }
87 #endif
88
89                 public abstract string XmlLang { get; }
90
91                 int Depth
92                 {
93                         get
94                         {
95                                 int cLevels = 0;
96                                 XPathNavigator nav = Clone ();
97                                 while (nav.MoveToParent ())
98                                         cLevels ++;
99                                 return cLevels;
100                         }
101                 }
102
103                 #endregion
104
105                 #region Methods
106
107                 public abstract XPathNavigator Clone ();
108
109                 public virtual XmlNodeOrder ComparePosition (XPathNavigator nav)
110                 {
111                         if (IsSamePosition (nav))
112                                 return XmlNodeOrder.Same;
113
114                         XPathNavigator nav1 = Clone ();
115                         XPathNavigator nav2 = nav.Clone ();
116
117                         int nDepth1 = nav1.Depth;
118                         int nDepth2 = nav2.Depth;
119
120                         if (nDepth1 > nDepth2)
121                         {
122                                 while (nDepth1 > nDepth2)
123                                 {
124                                         if (!nav1.MoveToParent ())
125                                                 break;
126                                         nDepth1 --;
127                                 }
128                                 if (nav1.IsSamePosition (nav2))
129                                         return XmlNodeOrder.After;
130                         }
131                         else if (nDepth1 < nDepth2)
132                         {
133                                 while (nDepth1 < nDepth2)
134                                 {
135                                         if (!nav2.MoveToParent ())
136                                                 break;
137                                         nDepth2 --;
138                                 }
139                                 if (nav1.IsSamePosition (nav2))
140                                         return XmlNodeOrder.Before;
141                         }
142
143                         XPathNavigator parent1 = nav1.Clone ();
144                         XPathNavigator parent2 = nav2.Clone ();
145                         while (parent1.MoveToParent () && parent2.MoveToParent ())
146                         {
147                                 if (parent1.IsSamePosition (parent2))
148                                 {
149                                         // the ordering is namespace, attribute, children
150                                         // assume that nav1 is before nav2, find counter-example
151                                         if (nav1.NodeType == XPathNodeType.Namespace)
152                                         {
153                                                 if (nav2.NodeType == XPathNodeType.Namespace)
154                                                 {
155                                                         // match namespaces
156                                                         while (nav2.MoveToNextNamespace ())
157                                                                 if (nav2.IsSamePosition (nav1))
158                                                                         return XmlNodeOrder.After;
159                                                 }
160                                         }
161                                         else if (nav1.NodeType == XPathNodeType.Attribute)
162                                         {
163                                                 if (nav2.NodeType == XPathNodeType.Namespace)
164                                                         return XmlNodeOrder.After;
165                                                 else if (nav2.NodeType == XPathNodeType.Attribute)
166                                                 {
167                                                         // match attributes
168                                                         while (nav2.MoveToNextAttribute ())
169                                                                 if (nav2.IsSamePosition (nav1))
170                                                                         return XmlNodeOrder.After;
171                                                 }
172                                         }
173                                         else
174                                         {
175                                                 switch (nav2.NodeType) {
176                                                 case XPathNodeType.Namespace:
177                                                 case XPathNodeType.Attribute:
178                                                         return XmlNodeOrder.After;
179                                                 }
180                                                 // match children
181                                                 while (nav2.MoveToNext ())
182                                                         if (nav2.IsSamePosition (nav1))
183                                                                 return XmlNodeOrder.After;
184                                         }
185                                         return XmlNodeOrder.Before;
186                                 }
187                                 nav1.MoveToParent ();
188                                 nav2.MoveToParent ();
189                         }
190                         return XmlNodeOrder.Unknown;
191                 }
192
193                 public virtual XPathExpression Compile (string xpath)
194                 {
195                         XPathParser parser = new XPathParser ();
196                         return new CompiledExpression (parser.Compile (xpath));
197                 }
198                 
199                 internal virtual XPathExpression Compile (string xpath, System.Xml.Xsl.IStaticXsltContext ctx)
200                 {
201                         XPathParser parser = new XPathParser (ctx);
202                         return new CompiledExpression (parser.Compile (xpath));
203                 }
204
205                 public virtual object Evaluate (string xpath)
206                 {
207                         return Evaluate (Compile (xpath));
208                 }
209
210                 public virtual object Evaluate (XPathExpression expr)
211                 {
212                         return Evaluate (expr, null);
213                 }
214
215                 public virtual object Evaluate (XPathExpression expr, XPathNodeIterator context)
216                 {
217                         return Evaluate (expr, context, null);
218                 }
219                 
220                 internal virtual object Evaluate (XPathExpression expr, XPathNodeIterator context, NSResolver ctx)
221                 {
222                         CompiledExpression cexpr = (CompiledExpression) expr;
223                         if (ctx == null)
224                                 ctx = cexpr.NamespaceManager;
225                         
226                         if (context == null)
227                                 context = new NullIterator (this, ctx);
228                         BaseIterator iterContext = (BaseIterator) context;
229                         iterContext.NamespaceManager = ctx;
230                         return cexpr.Evaluate (iterContext);
231                 }
232
233                 internal XPathNodeIterator EvaluateNodeSet (XPathExpression expr, XPathNodeIterator context, NSResolver ctx)
234                 {
235                         CompiledExpression cexpr = (CompiledExpression) expr;
236                         if (ctx == null)
237                                 ctx = cexpr.NamespaceManager;
238                         
239                         if (context == null)
240                                 context = new NullIterator (this, cexpr.NamespaceManager);
241                         BaseIterator iterContext = (BaseIterator) context;
242                         iterContext.NamespaceManager = ctx;
243                         return cexpr.EvaluateNodeSet (iterContext);
244                 }
245
246                 internal string EvaluateString (XPathExpression expr, XPathNodeIterator context, NSResolver ctx)
247                 {
248                         CompiledExpression cexpr = (CompiledExpression) expr;
249                         if (ctx == null)
250                                 ctx = cexpr.NamespaceManager;
251                         
252                         if (context == null)
253                                 context = new NullIterator (this, cexpr.NamespaceManager);
254                         BaseIterator iterContext = (BaseIterator) context;
255                         iterContext.NamespaceManager = ctx;
256                         return cexpr.EvaluateString (iterContext);
257                 }
258
259                 internal double EvaluateNumber (XPathExpression expr, XPathNodeIterator context, NSResolver ctx)
260                 {
261                         CompiledExpression cexpr = (CompiledExpression) expr;
262                         if (ctx == null)
263                                 ctx = cexpr.NamespaceManager;
264                         
265                         if (context == null)
266                                 context = new NullIterator (this, cexpr.NamespaceManager);
267                         BaseIterator iterContext = (BaseIterator) context;
268                         iterContext.NamespaceManager = ctx;
269                         return cexpr.EvaluateNumber (iterContext);
270                 }
271
272                 internal bool EvaluateBoolean (XPathExpression expr, XPathNodeIterator context, NSResolver ctx)
273                 {
274                         CompiledExpression cexpr = (CompiledExpression) expr;
275                         if (ctx == null)
276                                 ctx = cexpr.NamespaceManager;
277                         
278                         if (context == null)
279                                 context = new NullIterator (this, cexpr.NamespaceManager);
280                         BaseIterator iterContext = (BaseIterator) context;
281                         iterContext.NamespaceManager = ctx;
282                         return cexpr.EvaluateBoolean (iterContext);
283                 }
284
285                 public abstract string GetAttribute (string localName, string namespaceURI);
286
287                 public abstract string GetNamespace (string name);
288                 
289                 object ICloneable.Clone ()
290                 {
291                         return Clone ();
292                 }
293
294                 public virtual bool IsDescendant (XPathNavigator nav)
295                 {
296                         if (nav != null)
297                         {
298                                 nav = nav.Clone ();
299                                 while (nav.MoveToParent ())
300                                 {
301                                         if (IsSamePosition (nav))
302                                                 return true;
303                                 }
304                         }
305                         return false;
306                 }
307
308                 public abstract bool IsSamePosition (XPathNavigator other);
309
310                 public virtual bool Matches (string xpath)
311                 {
312                         return Matches (Compile (xpath));
313                 }
314
315                 public virtual bool Matches (XPathExpression expr)
316                 {
317                         Expression e = ((CompiledExpression) expr).ExpressionNode;
318                         if (e is ExprRoot)
319                                 return NodeType == XPathNodeType.Root;
320                         
321                         NodeTest nt = e as NodeTest;
322                         if (nt != null) {
323                                 switch (nt.Axis.Axis) {
324                                 case Axes.Child:
325                                 case Axes.Attribute:
326                                         break;
327                                 default:
328                                         throw new XPathException ("Only child and attribute pattern are allowed for a pattern.");
329                                 }
330                                 return nt.Match (((CompiledExpression)expr).NamespaceManager, this);
331                         }
332                         if (e is ExprFilter) {
333                                 do {
334                                         e = ((ExprFilter) e).LeftHandSide;
335                                 } while (e is ExprFilter);
336                                 
337                                 if (e is NodeTest && !((NodeTest) e).Match (((CompiledExpression) expr).NamespaceManager, this))
338                                         return false;
339                         }
340
341                         XPathResultType resultType = e.ReturnType;
342                         switch (resultType) {
343                         case XPathResultType.Any:
344                         case XPathResultType.NodeSet:
345                                 break;
346                         default:
347                                 return false;
348                         }
349
350                         switch (e.EvaluatedNodeType) {
351                         case XPathNodeType.Attribute:
352                         case XPathNodeType.Namespace:
353                                 if (NodeType != e.EvaluatedNodeType)
354                                         return false;
355                                 break;
356                         }
357
358                         XPathNodeIterator nodes;
359                         nodes = this.Select (expr);
360                         while (nodes.MoveNext ()) {
361                                 if (IsSamePosition (nodes.Current))
362                                         return true;
363                         }
364
365                         // ancestors might select this node.
366
367                         XPathNavigator navigator = Clone ();
368
369                         while (navigator.MoveToParent ()) {
370                                 nodes = navigator.Select (expr);
371
372                                 while (nodes.MoveNext ()) {
373                                         if (IsSamePosition (nodes.Current))
374                                                 return true;
375                                 }
376                         }
377
378                         return false;
379                 }
380
381                 public abstract bool MoveTo (XPathNavigator other);
382
383                 public abstract bool MoveToAttribute (string localName, string namespaceURI);
384
385                 public abstract bool MoveToFirst ();
386
387                 public abstract bool MoveToFirstAttribute ();
388
389                 public abstract bool MoveToFirstChild ();
390
391                 public bool MoveToFirstNamespace ()
392                 {
393                         return MoveToFirstNamespace (XPathNamespaceScope.All);
394                 }
395
396                 public abstract bool MoveToFirstNamespace (XPathNamespaceScope namespaceScope);
397
398                 public abstract bool MoveToId (string id);
399
400                 public abstract bool MoveToNamespace (string name);
401
402                 public abstract bool MoveToNext ();
403
404                 public abstract bool MoveToNextAttribute ();
405
406                 public bool MoveToNextNamespace ()
407                 {
408                         return MoveToNextNamespace (XPathNamespaceScope.All);
409                 }
410
411                 public abstract bool MoveToNextNamespace (XPathNamespaceScope namespaceScope);
412
413                 public abstract bool MoveToParent ();
414
415                 public abstract bool MoveToPrevious ();
416
417                 public abstract void MoveToRoot ();
418
419                 public virtual XPathNodeIterator Select (string xpath)
420                 {
421                         return Select (Compile (xpath));
422                 }
423
424                 public virtual XPathNodeIterator Select (XPathExpression expr)
425                 {
426                         return Select (expr, null);
427                 }
428                 
429                 internal virtual XPathNodeIterator Select (XPathExpression expr, NSResolver ctx)
430                 {
431                         CompiledExpression cexpr = (CompiledExpression) expr;
432                         if (ctx == null)
433                                 ctx = cexpr.NamespaceManager;
434                         
435                         BaseIterator iter = new NullIterator (this, ctx);
436                         return cexpr.EvaluateNodeSet (iter);
437                 }
438
439                 public virtual XPathNodeIterator SelectAncestors (XPathNodeType type, bool matchSelf)
440                 {
441                         Axes axis = (matchSelf) ? Axes.AncestorOrSelf : Axes.Ancestor;
442                         return SelectTest (new NodeTypeTest (axis, type));
443                 }
444
445                 public virtual XPathNodeIterator SelectAncestors (string name, string namespaceURI, bool matchSelf)
446                 {
447                         if (name == null)
448                                 throw new ArgumentNullException ("name");
449                         if (namespaceURI == null)
450                                 throw new ArgumentNullException ("namespaceURI");
451
452                         Axes axis = (matchSelf) ? Axes.AncestorOrSelf : Axes.Ancestor;
453                         XmlQualifiedName qname = new XmlQualifiedName (name, namespaceURI);
454                         return SelectTest (new NodeNameTest (axis, qname, true));
455                 }
456
457                 public virtual XPathNodeIterator SelectChildren (XPathNodeType type)
458                 {
459                         return SelectTest (new NodeTypeTest (Axes.Child, type));
460                 }
461
462                 public virtual XPathNodeIterator SelectChildren (string name, string namespaceURI)
463                 {
464                         if (name == null)
465                                 throw new ArgumentNullException ("name");
466                         if (namespaceURI == null)
467                                 throw new ArgumentNullException ("namespaceURI");
468
469                         Axes axis = Axes.Child;
470                         XmlQualifiedName qname = new XmlQualifiedName (name, namespaceURI);
471                         return SelectTest (new NodeNameTest (axis, qname, true));
472                 }
473
474                 public virtual XPathNodeIterator SelectDescendants (XPathNodeType type, bool matchSelf)
475                 {
476                         Axes axis = (matchSelf) ? Axes.DescendantOrSelf : Axes.Descendant;
477                         return SelectTest (new NodeTypeTest (axis, type));
478                 }
479
480                 public virtual XPathNodeIterator SelectDescendants (string name, string namespaceURI, bool matchSelf)
481                 {
482                         if (name == null)
483                                 throw new ArgumentNullException ("name");
484                         if (namespaceURI == null)
485                                 throw new ArgumentNullException ("namespaceURI");
486
487
488                         Axes axis = (matchSelf) ? Axes.DescendantOrSelf : Axes.Descendant;
489                         XmlQualifiedName qname = new XmlQualifiedName (name, namespaceURI);
490                         return SelectTest (new NodeNameTest (axis, qname, true));
491                 }
492
493                 internal XPathNodeIterator SelectTest (NodeTest test)
494                 {
495                         return test.EvaluateNodeSet (new NullIterator (this));
496                 }
497
498                 public override string ToString ()
499                 {
500                         return Value;
501                 }
502
503                 #endregion
504
505 #if NET_2_0
506
507                 [MonoTODO]
508                 public virtual bool CheckValidity (XmlSchemaSet schemas, ValidationEventHandler handler)
509                 {
510                         throw new NotImplementedException ();
511                 }
512
513                 [MonoTODO]
514                 public virtual object CopyAsObject (Type targetType)
515                 {
516                         throw new NotImplementedException ();
517                 }
518
519                 public virtual XPathNavigator CreateNavigator ()
520                 {
521                         return Clone ();
522                 }
523
524                 [MonoTODO]
525                 public virtual object Evaluate (string xpath, IXmlNamespaceResolver nsResolver)
526                 {
527                         return Evaluate (Compile (xpath), null, nsResolver);
528                 }
529
530                 [MonoTODO]
531                 public virtual IDictionary GetNamespacesInScope (XmlNamespaceScope scope)
532                 {
533                         throw new NotImplementedException ();
534                 }
535
536                 public virtual string LookupNamespace (string prefix)
537                 {
538                         return LookupNamespace (prefix, false);
539                 }
540
541                 [MonoTODO]
542                 public virtual string LookupNamespace (string prefix, bool atomizedNames)
543                 {
544                         throw new NotImplementedException ();
545                 }
546
547                 public virtual string LookupPrefix (string namespaceUri)
548                 {
549                         return LookupPrefix (namespaceUri, false);
550                 }
551
552                 [MonoTODO]
553                 public virtual string LookupPrefix (string namespaceUri, bool atomizedNames)
554                 {
555                         throw new NotImplementedException ();
556                 }
557
558                 [MonoTODO]
559                 public virtual XmlReader ReadSubtree ()
560                 {
561                         throw new NotImplementedException ();
562                 }
563
564                 public virtual XPathNavigator SelectSingleNode (string xpath)
565                 {
566                         return SelectSingleNode (xpath, null);
567                 }
568
569                 [MonoTODO]
570                 public virtual XPathNavigator SelectSingleNode (string xpath, IXmlNamespaceResolver nsResolver)
571                 {
572                         throw new NotImplementedException ();
573                 }
574
575                 public override object ValueAs (Type type)
576                 {
577                         return ValueAs (type, this);
578                 }
579
580                 [MonoTODO]
581                 public override object ValueAs (Type type, IXmlNamespaceResolver nsResolver)
582                 {
583                         throw new NotImplementedException ();
584                 }
585
586                 [MonoTODO]
587                 public virtual XmlWriter WriteSubtree ()
588                 {
589                         throw new NotImplementedException ();
590                 }
591
592                 [MonoTODO]
593                 public virtual string InnerXml {
594                         get { throw new NotImplementedException (); }
595                 }
596
597                 [MonoTODO]
598                 public override bool IsNode {
599                         get { throw new NotImplementedException (); }
600                 }
601
602                 [MonoTODO]
603                 public virtual IKeyComparer NavigatorComparer {
604                         get { throw new NotImplementedException (); }
605                 }
606
607                 [MonoTODO]
608                 public virtual string OuterXml {
609                         get { throw new NotImplementedException (); }
610                 }
611
612                 [MonoTODO]
613                 public virtual IXmlSchemaInfo SchemaInfo {
614                         get { throw new NotImplementedException (); }
615                 }
616
617                 [MonoTODO]
618                 public virtual object TypedValue {
619                         get { throw new NotImplementedException (); }
620                 }
621
622                 [MonoTODO]
623                 public virtual object UnderlyingObject {
624                         get { throw new NotImplementedException (); }
625                 }
626
627                 [MonoTODO]
628                 public override bool ValueAsBoolean {
629                         get { throw new NotImplementedException (); }
630                 }
631
632                 [MonoTODO]
633                 public override DateTime ValueAsDateTime {
634                         get { throw new NotImplementedException (); }
635                 }
636
637                 [MonoTODO]
638                 public override decimal ValueAsDecimal {
639                         get { throw new NotImplementedException (); }
640                 }
641
642                 [MonoTODO]
643                 public override double ValueAsDouble {
644                         get { throw new NotImplementedException (); }
645                 }
646
647                 [MonoTODO]
648                 public override int ValueAsInt32 {
649                         get { throw new NotImplementedException (); }
650                 }
651
652                 [MonoTODO]
653                 public override long ValueAsInt64 {
654                         get { throw new NotImplementedException (); }
655                 }
656
657                 [MonoTODO]
658                 public override ICollection ValueAsList {
659                         get { throw new NotImplementedException (); }
660                 }
661
662                 [MonoTODO]
663                 public override float ValueAsSingle {
664                         get { throw new NotImplementedException (); }
665                 }
666
667                 [MonoTODO]
668                 public virtual Type ValueType {
669                         get { throw new NotImplementedException (); }
670                 }
671
672                 [MonoTODO]
673                 public virtual XmlSchemaType XmlType {
674                         get { throw new NotImplementedException (); }
675                 }
676
677                 [MonoTODO]
678                 protected XmlReader GetValidatingReader (XmlSchemaSet schemas, ValidationEventHandler handler)
679                 {
680                         throw new NotImplementedException ();
681                 }
682 #endif
683         }
684 }