2005-12-13 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 #if NET_2_0
35 using System.Collections;
36 using System.Collections.Generic;
37 using System.Diagnostics;
38 #endif
39 using System.IO;
40 using System.Xml;
41 using System.Xml.Schema;
42 using Mono.Xml.XPath;
43
44 #if NET_2_0
45 using NSResolver = System.Xml.IXmlNamespaceResolver;
46 #else
47 using NSResolver = System.Xml.XmlNamespaceManager;
48 #endif
49
50 namespace System.Xml.XPath
51 {
52 #if NET_2_0
53         public abstract class XPathNavigator : XPathItem,
54                 ICloneable, IXPathNavigable, IXmlNamespaceResolver
55 #else
56         public abstract class XPathNavigator : ICloneable
57 #endif
58         {
59                 #region Static members
60 #if NET_2_0
61                 public static IEqualityComparer NavigatorComparer {
62                         get { return XPathNavigatorComparer.Instance; }
63                 }
64 #endif
65                 #endregion
66
67                 #region Constructor
68
69                 protected XPathNavigator ()
70                 {
71                 }
72
73                 #endregion
74
75                 #region Properties
76
77                 public abstract string BaseURI { get; }
78
79 #if NET_2_0
80                 public virtual bool CanEdit {
81                         get { return false; }
82                 }
83
84                 public virtual bool HasAttributes {
85                         get {
86                                 if (!MoveToFirstAttribute ())
87                                         return false;
88                                 MoveToParent ();
89                                 return true;
90                         }
91                 }
92
93                 public virtual bool HasChildren {
94                         get {
95                                 if (!MoveToFirstChild ())
96                                         return false;
97                                 MoveToParent ();
98                                 return true;
99                         }
100                 }
101 #else
102                 public abstract bool HasAttributes { get; }
103
104                 public abstract bool HasChildren { get; }
105 #endif
106
107                 public abstract bool IsEmptyElement { get; }
108
109                 public abstract string LocalName { get; }
110
111                 public abstract string Name { get; }
112
113                 public abstract string NamespaceURI { get; }
114
115                 public abstract XmlNameTable NameTable { get; }
116
117                 public abstract XPathNodeType NodeType { get; }
118
119                 public abstract string Prefix { get; }
120
121 #if NET_2_0
122                 public virtual string XmlLang {
123                         get {
124                                 XPathNavigator nav = Clone ();
125                                 switch (nav.NodeType) {
126                                 case XPathNodeType.Attribute:
127                                 case XPathNodeType.Namespace:
128                                         nav.MoveToParent ();
129                                         break;
130                                 }
131                                 do {
132                                         if (nav.MoveToAttribute ("lang", "http://www.w3.org/XML/1998/namespace"))
133                                                 return nav.Value;
134                                 } while (nav.MoveToParent ());
135                                 return String.Empty;
136                         }
137                 }
138 #else
139                 public abstract string Value { get; }
140
141                 public abstract string XmlLang { get; }
142 #endif
143
144                 #endregion
145
146                 #region Methods
147
148                 public abstract XPathNavigator Clone ();
149
150                 public virtual XmlNodeOrder ComparePosition (XPathNavigator nav)
151                 {
152                         if (IsSamePosition (nav))
153                                 return XmlNodeOrder.Same;
154
155                         // quick check for direct descendant
156                         if (IsDescendant (nav))
157                                 return XmlNodeOrder.Before;
158
159                         // quick check for direct ancestor
160                         if (nav.IsDescendant (this))
161                                 return XmlNodeOrder.After;
162
163                         XPathNavigator nav1 = Clone ();
164                         XPathNavigator nav2 = nav.Clone ();
165
166                         // check if document instance is the same.
167                         nav1.MoveToRoot ();
168                         nav2.MoveToRoot ();
169                         if (!nav1.IsSamePosition (nav2))
170                                 return XmlNodeOrder.Unknown;
171                         nav1.MoveTo (this);
172                         nav2.MoveTo (nav);
173
174                         int depth1 = 0;
175                         while (nav1.MoveToParent ())
176                                 depth1++;
177                         nav1.MoveTo (this);
178                         int depth2 = 0;
179                         while (nav2.MoveToParent ())
180                                 depth2++;
181                         nav2.MoveTo (nav);
182
183                         // find common parent depth
184                         int common = depth1;
185                         for (;common > depth2; common--)
186                                 nav1.MoveToParent ();
187                         for (int i = depth2; i > common; i--)
188                                 nav2.MoveToParent ();
189                         while (!nav1.IsSamePosition (nav2)) {
190                                 nav1.MoveToParent ();
191                                 nav2.MoveToParent ();
192                                 common--;
193                         }
194
195                         // For each this and target, move to the node that is 
196                         // ancestor of the node and child of the common parent.
197                         nav1.MoveTo (this);
198                         for (int i = depth1; i > common + 1; i--)
199                                 nav1.MoveToParent ();
200                         nav2.MoveTo (nav);
201                         for (int i = depth2; i > common + 1; i--)
202                                 nav2.MoveToParent ();
203
204                         // Those children of common parent are comparable.
205                         // namespace nodes precede to attributes, and they
206                         // precede to other nodes.
207                         if (nav1.NodeType == XPathNodeType.Namespace) {
208                                 if (nav2.NodeType != XPathNodeType.Namespace)
209                                         return XmlNodeOrder.Before;
210                                 while (nav1.MoveToNextNamespace ())
211                                         if (nav1.IsSamePosition (nav2))
212                                                 return XmlNodeOrder.Before;
213                                 return XmlNodeOrder.After;
214                         }
215                         if (nav2.NodeType == XPathNodeType.Namespace)
216                                 return XmlNodeOrder.After;
217                         if (nav1.NodeType == XPathNodeType.Attribute) {
218                                 if (nav2.NodeType != XPathNodeType.Attribute)
219                                         return XmlNodeOrder.Before;
220                                 while (nav1.MoveToNextAttribute ())
221                                         if (nav1.IsSamePosition (nav2))
222                                                 return XmlNodeOrder.Before;
223                                 return XmlNodeOrder.After;
224                         }
225                         while (nav1.MoveToNext ())
226                                 if (nav1.IsSamePosition (nav2))
227                                         return XmlNodeOrder.Before;
228                         return XmlNodeOrder.After;
229                 }
230
231                 public virtual XPathExpression Compile (string xpath)
232                 {
233                         return XPathExpression.Compile (xpath);
234                 }
235                 
236                 internal virtual XPathExpression Compile (string xpath, System.Xml.Xsl.IStaticXsltContext ctx)
237                 {
238                         return XPathExpression.Compile (xpath, null, ctx);
239                 }
240
241                 public virtual object Evaluate (string xpath)
242                 {
243                         return Evaluate (Compile (xpath));
244                 }
245
246                 public virtual object Evaluate (XPathExpression expr)
247                 {
248                         return Evaluate (expr, null);
249                 }
250
251                 public virtual object Evaluate (XPathExpression expr, XPathNodeIterator context)
252                 {
253                         return Evaluate (expr, context, null);
254                 }
255                 
256                 internal virtual object Evaluate (XPathExpression expr, XPathNodeIterator context, NSResolver ctx)
257                 {
258                         CompiledExpression cexpr = (CompiledExpression) expr;
259                         if (ctx == null)
260                                 ctx = cexpr.NamespaceManager;
261                         
262                         if (context == null)
263                                 context = new NullIterator (this, ctx);
264                         BaseIterator iterContext = (BaseIterator) context;
265                         iterContext.NamespaceManager = ctx;
266                         return cexpr.Evaluate (iterContext);
267                 }
268
269                 internal XPathNodeIterator EvaluateNodeSet (XPathExpression expr, XPathNodeIterator context, NSResolver ctx)
270                 {
271                         CompiledExpression cexpr = (CompiledExpression) expr;
272                         if (ctx == null)
273                                 ctx = cexpr.NamespaceManager;
274                         
275                         if (context == null)
276                                 context = new NullIterator (this, cexpr.NamespaceManager);
277                         BaseIterator iterContext = (BaseIterator) context;
278                         iterContext.NamespaceManager = ctx;
279                         return cexpr.EvaluateNodeSet (iterContext);
280                 }
281
282                 internal string EvaluateString (XPathExpression expr, XPathNodeIterator context, NSResolver ctx)
283                 {
284                         CompiledExpression cexpr = (CompiledExpression) expr;
285                         if (ctx == null)
286                                 ctx = cexpr.NamespaceManager;
287                         
288                         if (context == null)
289                                 context = new NullIterator (this, cexpr.NamespaceManager);
290                         BaseIterator iterContext = (BaseIterator) context;
291                         iterContext.NamespaceManager = ctx;
292                         return cexpr.EvaluateString (iterContext);
293                 }
294
295                 internal double EvaluateNumber (XPathExpression expr, XPathNodeIterator context, NSResolver ctx)
296                 {
297                         CompiledExpression cexpr = (CompiledExpression) expr;
298                         if (ctx == null)
299                                 ctx = cexpr.NamespaceManager;
300                         
301                         if (context == null)
302                                 context = new NullIterator (this, cexpr.NamespaceManager);
303                         BaseIterator iterContext = (BaseIterator) context;
304                         iterContext.NamespaceManager = ctx;
305                         return cexpr.EvaluateNumber (iterContext);
306                 }
307
308                 internal bool EvaluateBoolean (XPathExpression expr, XPathNodeIterator context, NSResolver ctx)
309                 {
310                         CompiledExpression cexpr = (CompiledExpression) expr;
311                         if (ctx == null)
312                                 ctx = cexpr.NamespaceManager;
313                         
314                         if (context == null)
315                                 context = new NullIterator (this, cexpr.NamespaceManager);
316                         BaseIterator iterContext = (BaseIterator) context;
317                         iterContext.NamespaceManager = ctx;
318                         return cexpr.EvaluateBoolean (iterContext);
319                 }
320
321 #if NET_2_0
322                 public virtual string GetAttribute (string localName, string namespaceURI)
323                 {
324                         if (!MoveToAttribute (localName, namespaceURI))
325                                 return String.Empty;
326                         string value = Value;
327                         MoveToParent ();
328                         return value;
329                 }
330
331                 public virtual string GetNamespace (string name)
332                 {
333                         if (!MoveToNamespace (name))
334                                 return String.Empty;
335                         string value = Value;
336                         MoveToParent ();
337                         return value;
338                 }
339
340 #else
341                 public abstract string GetAttribute (string localName, string namespaceURI);
342
343                 public abstract string GetNamespace (string name);
344 #endif
345                 
346                 object ICloneable.Clone ()
347                 {
348                         return Clone ();
349                 }
350
351                 public virtual bool IsDescendant (XPathNavigator nav)
352                 {
353                         if (nav != null)
354                         {
355                                 nav = nav.Clone ();
356                                 while (nav.MoveToParent ())
357                                 {
358                                         if (IsSamePosition (nav))
359                                                 return true;
360                                 }
361                         }
362                         return false;
363                 }
364
365                 public abstract bool IsSamePosition (XPathNavigator other);
366
367                 public virtual bool Matches (string xpath)
368                 {
369                         return Matches (Compile (xpath));
370                 }
371
372                 public virtual bool Matches (XPathExpression expr)
373                 {
374                         Expression e = ((CompiledExpression) expr).ExpressionNode;
375                         if (e is ExprRoot)
376                                 return NodeType == XPathNodeType.Root;
377                         
378                         NodeTest nt = e as NodeTest;
379                         if (nt != null) {
380                                 switch (nt.Axis.Axis) {
381                                 case Axes.Child:
382                                 case Axes.Attribute:
383                                         break;
384                                 default:
385                                         throw new XPathException ("Only child and attribute pattern are allowed for a pattern.");
386                                 }
387                                 return nt.Match (((CompiledExpression)expr).NamespaceManager, this);
388                         }
389                         if (e is ExprFilter) {
390                                 do {
391                                         e = ((ExprFilter) e).LeftHandSide;
392                                 } while (e is ExprFilter);
393                                 
394                                 if (e is NodeTest && !((NodeTest) e).Match (((CompiledExpression) expr).NamespaceManager, this))
395                                         return false;
396                         }
397
398                         XPathResultType resultType = e.ReturnType;
399                         switch (resultType) {
400                         case XPathResultType.Any:
401                         case XPathResultType.NodeSet:
402                                 break;
403                         default:
404                                 return false;
405                         }
406
407                         switch (e.EvaluatedNodeType) {
408                         case XPathNodeType.Attribute:
409                         case XPathNodeType.Namespace:
410                                 if (NodeType != e.EvaluatedNodeType)
411                                         return false;
412                                 break;
413                         }
414
415                         XPathNodeIterator nodes;
416                         nodes = this.Select (expr);
417                         while (nodes.MoveNext ()) {
418                                 if (IsSamePosition (nodes.Current))
419                                         return true;
420                         }
421
422                         // ancestors might select this node.
423
424                         XPathNavigator navigator = Clone ();
425
426                         while (navigator.MoveToParent ()) {
427                                 nodes = navigator.Select (expr);
428
429                                 while (nodes.MoveNext ()) {
430                                         if (IsSamePosition (nodes.Current))
431                                                 return true;
432                                 }
433                         }
434
435                         return false;
436                 }
437
438                 public abstract bool MoveTo (XPathNavigator other);
439
440 #if NET_2_0
441                 public virtual bool MoveToAttribute (string localName, string namespaceURI)
442                 {
443                         if (MoveToFirstAttribute ()) {
444                                 do {
445                                         if (LocalName == localName && NamespaceURI == namespaceURI)
446                                                 return true;
447                                 } while (MoveToNextAttribute ());
448                                 MoveToParent ();
449                         }
450                         return false;
451                 }
452
453                 public virtual bool MoveToNamespace (string name)
454                 {
455                         if (MoveToFirstNamespace ()) {
456                                 do {
457                                         if (LocalName == name)
458                                                 return true;
459                                 } while (MoveToNextNamespace ());
460                                 MoveToParent ();
461                         }
462                         return false;
463                 }
464
465                 /*
466                 public virtual bool MoveToFirst ()
467                 {
468                         if (MoveToPrevious ()) {
469                                 // It would be able to invoke MoveToPrevious() until the end, but this way would be much faster
470                                 MoveToParent ();
471                                 MoveToFirstChild ();
472                                 return true;
473                         }
474                         return false;
475                 }
476                 */
477
478                 public virtual bool MoveToFirst ()
479                 {
480                         return MoveToFirstImpl ();
481                 }
482
483                 public virtual void MoveToRoot ()
484                 {
485                         while (MoveToParent ())
486                                 ;
487                 }
488 #else
489                 public abstract bool MoveToAttribute (string localName, string namespaceURI);
490
491                 public abstract bool MoveToNamespace (string name);
492
493                 public abstract bool MoveToFirst ();
494
495                 public abstract void MoveToRoot ();
496 #endif
497
498                 internal bool MoveToFirstImpl ()
499                 {
500                         switch (NodeType) {
501                         case XPathNodeType.Attribute:
502                         case XPathNodeType.Namespace:
503                                 return false;
504                         default:
505                                 if (!MoveToParent ())
506                                         return false;
507                                 // Follow these 2 steps so that we can skip 
508                                 // some types of nodes .
509                                 MoveToFirstChild ();
510                                 return true;
511                         }
512                 }
513
514                 public abstract bool MoveToFirstAttribute ();
515
516                 public abstract bool MoveToFirstChild ();
517
518                 public bool MoveToFirstNamespace ()
519                 {
520                         return MoveToFirstNamespace (XPathNamespaceScope.All);
521                 }
522
523                 public abstract bool MoveToFirstNamespace (XPathNamespaceScope namespaceScope);
524
525                 public abstract bool MoveToId (string id);
526
527                 public abstract bool MoveToNext ();
528
529                 public abstract bool MoveToNextAttribute ();
530
531                 public bool MoveToNextNamespace ()
532                 {
533                         return MoveToNextNamespace (XPathNamespaceScope.All);
534                 }
535
536                 public abstract bool MoveToNextNamespace (XPathNamespaceScope namespaceScope);
537
538                 public abstract bool MoveToParent ();
539
540                 public abstract bool MoveToPrevious ();
541
542                 public virtual XPathNodeIterator Select (string xpath)
543                 {
544                         return Select (Compile (xpath));
545                 }
546
547                 public virtual XPathNodeIterator Select (XPathExpression expr)
548                 {
549                         return Select (expr, null);
550                 }
551                 
552                 internal virtual XPathNodeIterator Select (XPathExpression expr, NSResolver ctx)
553                 {
554                         CompiledExpression cexpr = (CompiledExpression) expr;
555                         if (ctx == null)
556                                 ctx = cexpr.NamespaceManager;
557                         
558                         BaseIterator iter = new NullIterator (this, ctx);
559                         return cexpr.EvaluateNodeSet (iter);
560                 }
561
562                 public virtual XPathNodeIterator SelectAncestors (XPathNodeType type, bool matchSelf)
563                 {
564                         Axes axis = (matchSelf) ? Axes.AncestorOrSelf : Axes.Ancestor;
565                         return SelectTest (new NodeTypeTest (axis, type));
566                 }
567
568                 public virtual XPathNodeIterator SelectAncestors (string name, string namespaceURI, bool matchSelf)
569                 {
570                         if (name == null)
571                                 throw new ArgumentNullException ("name");
572                         if (namespaceURI == null)
573                                 throw new ArgumentNullException ("namespaceURI");
574
575                         Axes axis = (matchSelf) ? Axes.AncestorOrSelf : Axes.Ancestor;
576                         XmlQualifiedName qname = new XmlQualifiedName (name, namespaceURI);
577                         return SelectTest (new NodeNameTest (axis, qname, true));
578                 }
579
580                 public virtual XPathNodeIterator SelectChildren (XPathNodeType type)
581                 {
582                         return SelectTest (new NodeTypeTest (Axes.Child, type));
583                 }
584
585                 public virtual XPathNodeIterator SelectChildren (string name, string namespaceURI)
586                 {
587                         if (name == null)
588                                 throw new ArgumentNullException ("name");
589                         if (namespaceURI == null)
590                                 throw new ArgumentNullException ("namespaceURI");
591
592                         Axes axis = Axes.Child;
593                         XmlQualifiedName qname = new XmlQualifiedName (name, namespaceURI);
594                         return SelectTest (new NodeNameTest (axis, qname, true));
595                 }
596
597                 public virtual XPathNodeIterator SelectDescendants (XPathNodeType type, bool matchSelf)
598                 {
599                         Axes axis = (matchSelf) ? Axes.DescendantOrSelf : Axes.Descendant;
600                         return SelectTest (new NodeTypeTest (axis, type));
601                 }
602
603                 public virtual XPathNodeIterator SelectDescendants (string name, string namespaceURI, bool matchSelf)
604                 {
605                         if (name == null)
606                                 throw new ArgumentNullException ("name");
607                         if (namespaceURI == null)
608                                 throw new ArgumentNullException ("namespaceURI");
609
610
611                         Axes axis = (matchSelf) ? Axes.DescendantOrSelf : Axes.Descendant;
612                         XmlQualifiedName qname = new XmlQualifiedName (name, namespaceURI);
613                         return SelectTest (new NodeNameTest (axis, qname, true));
614                 }
615
616                 internal XPathNodeIterator SelectTest (NodeTest test)
617                 {
618                         return test.EvaluateNodeSet (new NullIterator (this));
619                 }
620
621                 public override string ToString ()
622                 {
623                         return Value;
624                 }
625
626                 #endregion
627
628 #if NET_2_0
629
630                 public virtual bool CheckValidity (XmlSchemaSet schemas, ValidationEventHandler handler)
631                 {
632                         XmlReaderSettings settings = new XmlReaderSettings ();
633                         settings.NameTable = NameTable;
634                         settings.SetSchemas (schemas);
635                         settings.ValidationEventHandler += handler;
636                         settings.ValidationType = ValidationType.Schema;
637                         try {
638                                 XmlReader r = XmlReader.Create (
639                                         ReadSubtree (), settings);
640                                 while (!r.EOF)
641                                         r.Read ();
642                         } catch (XmlSchemaValidationException) {
643                                 return false;
644                         }
645                         return true;
646                 }
647
648                 public virtual XPathNavigator CreateNavigator ()
649                 {
650                         return Clone ();
651                 }
652
653                 [MonoTODO]
654                 public virtual object Evaluate (string xpath, IXmlNamespaceResolver nsResolver)
655                 {
656                         return Evaluate (Compile (xpath), null, nsResolver);
657                 }
658
659                 [MonoTODO]
660                 public virtual IDictionary<string, string> GetNamespacesInScope (XmlNamespaceScope scope)
661                 {
662                         IDictionary<string, string> table = new Dictionary<string, string> ();
663                         XPathNamespaceScope xpscope =
664                                 scope == XmlNamespaceScope.Local ?
665                                         XPathNamespaceScope.Local :
666                                 scope == XmlNamespaceScope.ExcludeXml ?
667                                         XPathNamespaceScope.ExcludeXml :
668                                 XPathNamespaceScope.All;
669                         XPathNavigator nav = Clone ();
670                         if (nav.NodeType != XPathNodeType.Element)
671                                 nav.MoveToParent ();
672                         if (!nav.MoveToFirstNamespace (xpscope))
673                                 return table;
674                         do {
675                                 table.Add (nav.Name, nav.Value);
676                         } while (nav.MoveToNextNamespace (xpscope));
677                         return table;
678                 }
679
680                 public virtual string LookupNamespace (string prefix)
681                 {
682                         XPathNavigator nav = Clone ();
683                         if (nav.NodeType != XPathNodeType.Element)
684                                 nav.MoveToParent ();
685                         if (nav.MoveToNamespace (prefix))
686                                 return nav.Value;
687                         return null;
688                 }
689
690                 public virtual string LookupPrefix (string namespaceUri)
691                 {
692                         XPathNavigator nav = Clone ();
693                         if (nav.NodeType != XPathNodeType.Element)
694                                 nav.MoveToParent ();
695                         if (!nav.MoveToFirstNamespace ())
696                                 return null;
697                         do {
698                                 if (nav.Value == namespaceUri)
699                                         return nav.Name;
700                         } while (nav.MoveToNextNamespace ());
701                         return null;
702                 }
703
704                 private bool MoveTo (XPathNodeIterator iter)
705                 {
706                         if (iter.MoveNext ()) {
707                                 MoveTo (iter.Current);
708                                 return true;
709                         }
710                         else
711                                 return false;
712                 }
713
714                 public virtual bool MoveToChild (XPathNodeType type)
715                 {
716                         return MoveTo (SelectChildren (type));
717                 }
718
719                 public virtual bool MoveToChild (string localName, string namespaceURI)
720                 {
721                         return MoveTo (SelectChildren (localName, namespaceURI));
722                 }
723
724                 public virtual bool MoveToNext (string localName, string namespaceURI)
725                 {
726                         XPathNavigator nav = Clone ();
727                         while (nav.MoveToNext ()) {
728                                 if (nav.LocalName == localName &&
729                                         nav.NamespaceURI == namespaceURI) {
730                                         MoveTo (nav);
731                                         return true;
732                                 }
733                         }
734                         return false;
735                 }
736
737                 public virtual bool MoveToNext (XPathNodeType type)
738                 {
739                         XPathNavigator nav = Clone ();
740                         while (nav.MoveToNext ()) {
741                                 if (nav.NodeType == type) {
742                                         MoveTo (nav);
743                                         return true;
744                                 }
745                         }
746                         return false;
747                 }
748
749                 public virtual bool MoveToFollowing (string localName,
750                         string namespaceURI)
751                 {
752                         return MoveToFollowing (localName, namespaceURI, null);
753                 }
754
755                 public virtual bool MoveToFollowing (string localName,
756                         string namespaceURI, XPathNavigator end)
757                 {
758                         if (localName == null)
759                                 throw new ArgumentNullException ("localName");
760                         if (namespaceURI == null)
761                                 throw new ArgumentNullException ("namespaceURI");
762                         localName = NameTable.Get (localName);
763                         if (localName == null)
764                                 return false;
765                         namespaceURI = NameTable.Get (namespaceURI);
766                         if (namespaceURI == null)
767                                 return false;
768
769                         XPathNavigator nav = Clone ();
770                         switch (nav.NodeType) {
771                         case XPathNodeType.Attribute:
772                         case XPathNodeType.Namespace:
773                                 nav.MoveToParent ();
774                                 break;
775                         }
776                         do {
777                                 if (!nav.MoveToFirstChild ()) {
778                                         do {
779                                                 if (!nav.MoveToNext ()) {
780                                                         if (!nav.MoveToParent ())
781                                                                 return false;
782                                                 }
783                                                 else
784                                                         break;
785                                         } while (true);
786                                 }
787                                 if (end != null && end.IsSamePosition (nav))
788                                         return false;
789                                 if (object.ReferenceEquals (localName, nav.LocalName) &&
790                                         object.ReferenceEquals (namespaceURI, nav.NamespaceURI)) {
791                                         MoveTo (nav);
792                                         return true;
793                                 }
794                         } while (true);
795                 }
796
797                 public virtual bool MoveToFollowing (XPathNodeType type)
798                 {
799                         return MoveToFollowing (type, null);
800                 }
801
802                 public virtual bool MoveToFollowing (XPathNodeType type,
803                         XPathNavigator end)
804                 {
805                         if (type == XPathNodeType.Root)
806                                 return false; // will never match
807                         XPathNavigator nav = Clone ();
808                         switch (nav.NodeType) {
809                         case XPathNodeType.Attribute:
810                         case XPathNodeType.Namespace:
811                                 nav.MoveToParent ();
812                                 break;
813                         }
814                         do {
815                                 if (!nav.MoveToFirstChild ()) {
816                                         do {
817                                                 if (!nav.MoveToNext ()) {
818                                                         if (!nav.MoveToParent ())
819                                                                 return false;
820                                                 }
821                                                 else
822                                                         break;
823                                         } while (true);
824                                 }
825                                 if (end != null && end.IsSamePosition (nav))
826                                         return false;
827                                 if (nav.NodeType == type) {
828                                         MoveTo (nav);
829                                         return true;
830                                 }
831                         } while (true);
832                 }
833
834                 [MonoTODO]
835                 public virtual XmlReader ReadSubtree ()
836                 {
837                         return new XPathNavigatorReader (this);
838                 }
839
840                 public virtual XPathNodeIterator Select (string xpath, IXmlNamespaceResolver nsResolver)
841                 {
842                         return Select (Compile (xpath), nsResolver);
843                 }
844
845                 public virtual XPathNavigator SelectSingleNode (string xpath)
846                 {
847                         return SelectSingleNode (xpath, null);
848                 }
849
850                 public virtual XPathNavigator SelectSingleNode (string xpath, IXmlNamespaceResolver nsResolver)
851                 {
852                         XPathExpression expr = Compile (xpath);
853                         expr.SetContext (nsResolver);
854                         return SelectSingleNode (expr);
855                 }
856
857                 public virtual XPathNavigator SelectSingleNode (XPathExpression expression)
858                 {
859                         XPathNodeIterator iter = Select (expression);
860                         if (iter.MoveNext ())
861                                 return iter.Current;
862                         else
863                                 return null;
864                 }
865
866                 [MonoTODO]
867                 public override object ValueAs (Type type, IXmlNamespaceResolver nsResolver)
868                 {
869                         throw new NotImplementedException ();
870                 }
871
872                 [MonoTODO]
873                 public virtual void WriteSubtree (XmlWriter writer)
874                 {
875                         XmlReader st = ReadSubtree ();
876                         writer.WriteNode (st, false);
877                 }
878
879                 [MonoTODO]
880                 public virtual string InnerXml {
881                         get {
882                                 XmlReader r = ReadSubtree ();
883                                 r.Read (); // start
884                                 // skip the element itself (or will reach to 
885                                 // EOF if other than element) unless writing
886                                 // doc itself
887                                 int depth = r.Depth;
888                                 if (NodeType != XPathNodeType.Root)
889                                         r.Read ();
890                                 StringWriter sw = new StringWriter ();
891                                 XmlWriter xtw = XmlWriter.Create (sw);
892                                 while (!r.EOF && r.Depth > depth)
893                                         xtw.WriteNode (r, false);
894                                 return sw.ToString ();
895                         }
896                         set {
897                                 DeleteChildren ();
898                                 if (NodeType == XPathNodeType.Attribute) {
899                                         SetValue (value);
900                                         return;
901                                 }
902                                 AppendChild (value);
903                         }
904                 }
905
906                 [MonoTODO]
907                 public override bool IsNode {
908                         get { return true; }
909                 }
910
911                 [MonoTODO]
912                 public virtual string OuterXml {
913                         get {
914                                 StringWriter sw = new StringWriter ();
915                                 XmlTextWriter xtw = new XmlTextWriter (sw);
916                                 WriteSubtree (xtw);
917                                 xtw.Close ();
918                                 return sw.ToString ();
919                         }
920                         set {
921                                 switch (NodeType) {
922                                 case XPathNodeType.Root:
923                                 case XPathNodeType.Attribute:
924                                 case XPathNodeType.Namespace:
925                                         throw new XmlException ("Setting OuterXml Root, Attribute and Namespace is not supported.");
926                                 }
927
928                                 DeleteSelf ();
929                                 AppendChild (value);
930                                 MoveToFirstChild ();
931                         }
932                 }
933
934                 [MonoTODO]
935                 public virtual IXmlSchemaInfo SchemaInfo {
936                         get {
937                                 return null;
938                         }
939                 }
940
941                 [MonoTODO]
942                 public override object TypedValue {
943                         get {
944                                 switch (NodeType) {
945                                 case XPathNodeType.Element:
946                                 case XPathNodeType.Attribute:
947                                         if (XmlType == null)
948                                                 break;
949                                         XmlSchemaDatatype dt = XmlType.Datatype;
950                                         if (dt == null)
951                                                 break;
952                                         return dt.ParseValue (Value, NameTable, this as IXmlNamespaceResolver);
953                                 }
954                                 return Value;
955                         }
956                 }
957
958                 [MonoTODO]
959                 public virtual object UnderlyingObject {
960                         get { throw new NotImplementedException (); }
961                 }
962
963                 public override bool ValueAsBoolean {
964                         get { return XQueryConvert.StringToBoolean (Value); }
965                 }
966
967                 public override DateTime ValueAsDateTime {
968                         get { return XmlConvert.ToDateTime (Value); }
969                 }
970
971                 public override double ValueAsDouble {
972                         get { return XQueryConvert.StringToDouble (Value); }
973                 }
974
975                 public override int ValueAsInt {
976                         get { return XQueryConvert.StringToInt (Value); }
977                 }
978
979                 public override long ValueAsLong {
980                         get { return XQueryConvert.StringToInteger (Value); }
981                 }
982
983                 public override Type ValueType {
984                         get {
985                                 return SchemaInfo != null &&
986                                         SchemaInfo.SchemaType != null &&
987                                         SchemaInfo.SchemaType.Datatype != null ?
988                                         SchemaInfo.SchemaType.Datatype.ValueType
989                                         : null;
990                         }
991                 }
992
993                 [MonoTODO]
994                 public override XmlSchemaType XmlType {
995                         get {
996                                 if (SchemaInfo != null)
997                                         return SchemaInfo.SchemaType;
998                                 return null;
999                         }
1000                 }
1001
1002                 private XmlReader CreateFragmentReader (string fragment)
1003                 {
1004                         XmlReaderSettings settings = new XmlReaderSettings ();
1005                         settings.ConformanceLevel = ConformanceLevel.Fragment;
1006                         XmlNamespaceManager nsmgr = new XmlNamespaceManager (NameTable);
1007                         foreach (KeyValuePair<string,string> nss in GetNamespacesInScope (XmlNamespaceScope.All))
1008                                 nsmgr.AddNamespace (nss.Key, nss.Value);
1009                         return XmlReader.Create (
1010                                 new StringReader (fragment),
1011                                 settings,
1012                                 new XmlParserContext (NameTable, nsmgr, null, XmlSpace.None));
1013                 }
1014
1015                 // must override it.
1016                 public virtual XmlWriter AppendChild ()
1017                 {
1018                         throw new NotSupportedException ();
1019                 }
1020
1021                 public virtual void AppendChild (
1022                         string xmlFragments)
1023                 {
1024                         AppendChild (CreateFragmentReader (xmlFragments));
1025                 }
1026
1027                 public virtual void AppendChild (
1028                         XmlReader reader)
1029                 {
1030                         XmlWriter w = AppendChild ();
1031                         while (!reader.EOF)
1032                                 w.WriteNode (reader, false);
1033                         w.Close ();
1034                 }
1035
1036                 [MonoTODO]
1037                 public virtual void AppendChild (
1038                         XPathNavigator nav)
1039                 {
1040                         AppendChild (new XPathNavigatorReader (nav));
1041                 }
1042
1043                 public virtual void AppendChildElement (string prefix, string name, string ns, string value)
1044                 {
1045                         XmlWriter xw = AppendChild ();
1046                         xw.WriteStartElement (prefix, name, ns);
1047                         xw.WriteString (value);
1048                         xw.WriteEndElement ();
1049                         xw.Close ();
1050                 }
1051
1052                 public virtual void CreateAttribute (string prefix, string localName, string namespaceURI, string value)
1053                 {
1054                         using (XmlWriter w = CreateAttributes ()) {
1055                                 w.WriteAttributeString (prefix, localName, namespaceURI, value);
1056                         }
1057                 }
1058
1059                 // must override it.
1060                 public virtual XmlWriter CreateAttributes ()
1061                 {
1062                         throw new NotSupportedException ();
1063                 }
1064
1065                 // must override it.
1066                 public virtual void DeleteSelf ()
1067                 {
1068                         throw new NotSupportedException ();
1069                 }
1070
1071                 // must override it.
1072                 public virtual void DeleteRange (XPathNavigator nav)
1073                 {
1074                         throw new NotSupportedException ();
1075                 }
1076
1077                 public virtual XmlWriter ReplaceRange (XPathNavigator nav)
1078                 {
1079                         throw new NotSupportedException ();
1080                 }
1081         
1082                 public virtual XmlWriter InsertAfter ()
1083                 {
1084                         switch (NodeType) {
1085                         case XPathNodeType.Root:
1086                         case XPathNodeType.Attribute:
1087                         case XPathNodeType.Namespace:
1088                                 throw new InvalidOperationException (String.Format ("Insertion after {0} is not allowed.", NodeType));
1089                         }
1090                         XPathNavigator nav = Clone ();
1091                         if (nav.MoveToNext ())
1092                                 return nav.InsertBefore ();
1093                         else if (nav.MoveToParent ())
1094                                 return nav.AppendChild ();
1095                         else
1096                                 throw new InvalidOperationException ("Could not move to parent to insert sibling node");
1097                 }
1098
1099                 public virtual void InsertAfter (string xmlFragments)
1100                 {
1101                         InsertAfter (CreateFragmentReader (xmlFragments));
1102                 }
1103
1104                 public virtual void InsertAfter (XmlReader reader)
1105                 {
1106                         using (XmlWriter w = InsertAfter ()) {
1107                                 w.WriteNode (reader, false);
1108                         }
1109                 }
1110
1111                 [MonoTODO]
1112                 public virtual void InsertAfter (XPathNavigator nav)
1113                 {
1114                         InsertAfter (new XPathNavigatorReader (nav));
1115                 }
1116
1117                 public virtual XmlWriter InsertBefore ()
1118                 {
1119                         throw new NotSupportedException ();
1120                 }
1121
1122                 public virtual void InsertBefore (string xmlFragments)
1123                 {
1124                         InsertBefore (CreateFragmentReader (xmlFragments));
1125                 }
1126
1127                 public virtual void InsertBefore (XmlReader reader)
1128                 {
1129                         using (XmlWriter w = InsertBefore ()) {
1130                                 w.WriteNode (reader, false);
1131                         }
1132                 }
1133
1134                 [MonoTODO]
1135                 public virtual void InsertBefore (XPathNavigator nav)
1136                 {
1137                         InsertBefore (new XPathNavigatorReader (nav));
1138                 }
1139
1140                 public virtual void InsertElementAfter (string prefix, 
1141                         string localName, string namespaceURI, string value)
1142                 {
1143                         using (XmlWriter w = InsertAfter ()) {
1144                                 w.WriteElementString (prefix, localName, namespaceURI, value);
1145                         }
1146                 }
1147
1148                 public virtual void InsertElementBefore (string prefix, 
1149                         string localName, string namespaceURI, string value)
1150                 {
1151                         using (XmlWriter w = InsertBefore ()) {
1152                                 w.WriteElementString (prefix, localName, namespaceURI, value);
1153                         }
1154                 }
1155
1156                 public virtual XmlWriter PrependChild ()
1157                 {
1158                         XPathNavigator nav = Clone ();
1159                         if (nav.MoveToFirstChild ())
1160                                 return nav.InsertBefore ();
1161                         else
1162                                 return AppendChild ();
1163                 }
1164
1165                 public virtual void PrependChild (string xmlFragments)
1166                 {
1167                         PrependChild (CreateFragmentReader (xmlFragments));
1168                 }
1169
1170                 public virtual void PrependChild (XmlReader reader)
1171                 {
1172                         using (XmlWriter w = PrependChild ()) {
1173                                 w.WriteNode (reader, false);
1174                         }
1175                 }
1176
1177                 [MonoTODO]
1178                 public virtual void PrependChild (XPathNavigator nav)
1179                 {
1180                         PrependChild (new XPathNavigatorReader (nav));
1181                 }
1182
1183                 public virtual void PrependChildElement (string prefix, 
1184                         string localName, string namespaceURI, string value)
1185                 {
1186                         using (XmlWriter w = PrependChild ()) {
1187                                 w.WriteElementString (prefix, localName, namespaceURI, value);
1188                         }
1189                 }
1190
1191                 public virtual void ReplaceSelf (string xmlFragment)
1192                 {
1193                         ReplaceSelf (CreateFragmentReader (xmlFragment));
1194                 }
1195
1196                 // must override it.
1197                 public virtual void ReplaceSelf (XmlReader reader)
1198                 {
1199                         throw new NotSupportedException ();
1200                 }
1201
1202                 [MonoTODO]
1203                 public virtual void ReplaceSelf (XPathNavigator navigator)
1204                 {
1205                         ReplaceSelf (new XPathNavigatorReader (navigator));
1206                 }
1207
1208                 // Dunno the exact purpose, but maybe internal editor use
1209                 [MonoTODO]
1210                 public virtual void SetTypedValue (object value)
1211                 {
1212                         throw new NotSupportedException ();
1213                 }
1214
1215                 public virtual void SetValue (string value)
1216                 {
1217                         throw new NotSupportedException ();
1218                 }
1219
1220                 [MonoTODO]
1221                 private void DeleteChildren ()
1222                 {
1223                         switch (NodeType) {
1224                         case XPathNodeType.Namespace:
1225                                 throw new InvalidOperationException ("Removing namespace node content is not supported.");
1226                         case XPathNodeType.Attribute:
1227                                 return;
1228                         case XPathNodeType.Text:
1229                         case XPathNodeType.SignificantWhitespace:
1230                         case XPathNodeType.Whitespace:
1231                         case XPathNodeType.ProcessingInstruction:
1232                         case XPathNodeType.Comment:
1233                                 DeleteSelf ();
1234                                 return;
1235                         }
1236                         if (!HasChildren)
1237                                 return;
1238                         XPathNavigator nav = Clone ();
1239                         nav.MoveToFirstChild ();
1240                         while (!nav.IsSamePosition (this))
1241                                 nav.DeleteSelf ();
1242                 }
1243 #endif
1244         }
1245 }