2 // System.Xml.XPath.XPathNavigator
5 // Jason Diamond (jason@injektilo.org)
6 // Atsushi Enomoto (atsushi@ximian.com)
8 // (C) 2002 Jason Diamond http://injektilo.org/
9 // (C) 2004 Novell Inc.
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:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
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.
34 using System.Collections;
36 using System.Collections.Generic;
37 using System.Diagnostics;
42 using System.Xml.Schema;
46 using NSResolver = System.Xml.IXmlNamespaceResolver;
48 using NSResolver = System.Xml.XmlNamespaceManager;
51 namespace System.Xml.XPath
54 public abstract class XPathNavigator : XPathItem,
55 ICloneable, IXPathNavigable, IXmlNamespaceResolver
57 public abstract class XPathNavigator : ICloneable
60 class EnumerableIterator : XPathNodeIterator
66 public EnumerableIterator (IEnumerable source, int pos)
69 for (int i = 0; i < pos; i++)
73 public override XPathNodeIterator Clone ()
75 return new EnumerableIterator (source, pos);
78 public override bool MoveNext ()
81 e = source.GetEnumerator ();
88 public override int CurrentPosition {
92 public override XPathNavigator Current {
93 get { return pos == 0 ? null : (XPathNavigator) e.Current; }
97 #region Static members
99 public static IEqualityComparer NavigatorComparer {
100 get { return XPathNavigatorComparer.Instance; }
107 protected XPathNavigator ()
115 public abstract string BaseURI { get; }
118 public virtual bool CanEdit {
119 get { return false; }
122 public virtual bool HasAttributes {
124 if (!MoveToFirstAttribute ())
131 public virtual bool HasChildren {
133 if (!MoveToFirstChild ())
140 public abstract bool HasAttributes { get; }
142 public abstract bool HasChildren { get; }
145 public abstract bool IsEmptyElement { get; }
147 public abstract string LocalName { get; }
149 public abstract string Name { get; }
151 public abstract string NamespaceURI { get; }
153 public abstract XmlNameTable NameTable { get; }
155 public abstract XPathNodeType NodeType { get; }
157 public abstract string Prefix { get; }
160 public virtual string XmlLang {
162 XPathNavigator nav = Clone ();
163 switch (nav.NodeType) {
164 case XPathNodeType.Attribute:
165 case XPathNodeType.Namespace:
170 if (nav.MoveToAttribute ("lang", "http://www.w3.org/XML/1998/namespace"))
172 } while (nav.MoveToParent ());
177 public abstract string Value { get; }
179 public abstract string XmlLang { get; }
186 public abstract XPathNavigator Clone ();
188 public virtual XmlNodeOrder ComparePosition (XPathNavigator nav)
190 if (IsSamePosition (nav))
191 return XmlNodeOrder.Same;
193 // quick check for direct descendant
194 if (IsDescendant (nav))
195 return XmlNodeOrder.Before;
197 // quick check for direct ancestor
198 if (nav.IsDescendant (this))
199 return XmlNodeOrder.After;
201 XPathNavigator nav1 = Clone ();
202 XPathNavigator nav2 = nav.Clone ();
204 // check if document instance is the same.
207 if (!nav1.IsSamePosition (nav2))
208 return XmlNodeOrder.Unknown;
213 while (nav1.MoveToParent ())
217 while (nav2.MoveToParent ())
221 // find common parent depth
223 for (;common > depth2; common--)
224 nav1.MoveToParent ();
225 for (int i = depth2; i > common; i--)
226 nav2.MoveToParent ();
227 while (!nav1.IsSamePosition (nav2)) {
228 nav1.MoveToParent ();
229 nav2.MoveToParent ();
233 // For each this and target, move to the node that is
234 // ancestor of the node and child of the common parent.
236 for (int i = depth1; i > common + 1; i--)
237 nav1.MoveToParent ();
239 for (int i = depth2; i > common + 1; i--)
240 nav2.MoveToParent ();
242 // Those children of common parent are comparable.
243 // namespace nodes precede to attributes, and they
244 // precede to other nodes.
245 if (nav1.NodeType == XPathNodeType.Namespace) {
246 if (nav2.NodeType != XPathNodeType.Namespace)
247 return XmlNodeOrder.Before;
248 while (nav1.MoveToNextNamespace ())
249 if (nav1.IsSamePosition (nav2))
250 return XmlNodeOrder.Before;
251 return XmlNodeOrder.After;
253 if (nav2.NodeType == XPathNodeType.Namespace)
254 return XmlNodeOrder.After;
255 if (nav1.NodeType == XPathNodeType.Attribute) {
256 if (nav2.NodeType != XPathNodeType.Attribute)
257 return XmlNodeOrder.Before;
258 while (nav1.MoveToNextAttribute ())
259 if (nav1.IsSamePosition (nav2))
260 return XmlNodeOrder.Before;
261 return XmlNodeOrder.After;
263 while (nav1.MoveToNext ())
264 if (nav1.IsSamePosition (nav2))
265 return XmlNodeOrder.Before;
266 return XmlNodeOrder.After;
269 public virtual XPathExpression Compile (string xpath)
271 return XPathExpression.Compile (xpath);
274 internal virtual XPathExpression Compile (string xpath, System.Xml.Xsl.IStaticXsltContext ctx)
276 return XPathExpression.Compile (xpath, null, ctx);
279 public virtual object Evaluate (string xpath)
281 return Evaluate (Compile (xpath));
284 public virtual object Evaluate (XPathExpression expr)
286 return Evaluate (expr, null);
289 public virtual object Evaluate (XPathExpression expr, XPathNodeIterator context)
291 return Evaluate (expr, context, null);
294 BaseIterator ToBaseIterator (XPathNodeIterator iter, NSResolver ctx)
296 BaseIterator i = iter as BaseIterator;
298 i = new WrapperIterator (iter, ctx);
302 object Evaluate (XPathExpression expr, XPathNodeIterator context, NSResolver ctx)
304 CompiledExpression cexpr = (CompiledExpression) expr;
306 ctx = cexpr.NamespaceManager;
309 context = new NullIterator (this, ctx);
310 BaseIterator iterContext = ToBaseIterator (context, ctx);
311 iterContext.NamespaceManager = ctx;
312 return cexpr.Evaluate (iterContext);
315 internal XPathNodeIterator EvaluateNodeSet (XPathExpression expr, XPathNodeIterator context, NSResolver ctx)
317 CompiledExpression cexpr = (CompiledExpression) expr;
319 ctx = cexpr.NamespaceManager;
322 context = new NullIterator (this, cexpr.NamespaceManager);
323 BaseIterator iterContext = ToBaseIterator (context, ctx);
324 iterContext.NamespaceManager = ctx;
325 return cexpr.EvaluateNodeSet (iterContext);
328 internal string EvaluateString (XPathExpression expr, XPathNodeIterator context, NSResolver ctx)
330 CompiledExpression cexpr = (CompiledExpression) expr;
332 ctx = cexpr.NamespaceManager;
335 context = new NullIterator (this, cexpr.NamespaceManager);
336 BaseIterator iterContext = ToBaseIterator (context, ctx);
337 return cexpr.EvaluateString (iterContext);
340 internal double EvaluateNumber (XPathExpression expr, XPathNodeIterator context, NSResolver ctx)
342 CompiledExpression cexpr = (CompiledExpression) expr;
344 ctx = cexpr.NamespaceManager;
347 context = new NullIterator (this, cexpr.NamespaceManager);
348 BaseIterator iterContext = ToBaseIterator (context, ctx);
349 iterContext.NamespaceManager = ctx;
350 return cexpr.EvaluateNumber (iterContext);
353 internal bool EvaluateBoolean (XPathExpression expr, XPathNodeIterator context, NSResolver ctx)
355 CompiledExpression cexpr = (CompiledExpression) expr;
357 ctx = cexpr.NamespaceManager;
360 context = new NullIterator (this, cexpr.NamespaceManager);
361 BaseIterator iterContext = ToBaseIterator (context, ctx);
362 iterContext.NamespaceManager = ctx;
363 return cexpr.EvaluateBoolean (iterContext);
367 public virtual string GetAttribute (string localName, string namespaceURI)
369 if (!MoveToAttribute (localName, namespaceURI))
371 string value = Value;
376 public virtual string GetNamespace (string name)
378 if (!MoveToNamespace (name))
380 string value = Value;
386 public abstract string GetAttribute (string localName, string namespaceURI);
388 public abstract string GetNamespace (string name);
391 object ICloneable.Clone ()
396 public virtual bool IsDescendant (XPathNavigator nav)
401 while (nav.MoveToParent ())
403 if (IsSamePosition (nav))
410 public abstract bool IsSamePosition (XPathNavigator other);
412 public virtual bool Matches (string xpath)
414 return Matches (Compile (xpath));
417 public virtual bool Matches (XPathExpression expr)
419 Expression e = ((CompiledExpression) expr).ExpressionNode;
421 return NodeType == XPathNodeType.Root;
423 NodeTest nt = e as NodeTest;
425 switch (nt.Axis.Axis) {
430 throw new XPathException ("Only child and attribute pattern are allowed for a pattern.");
432 return nt.Match (((CompiledExpression)expr).NamespaceManager, this);
434 if (e is ExprFilter) {
436 e = ((ExprFilter) e).LeftHandSide;
437 } while (e is ExprFilter);
439 if (e is NodeTest && !((NodeTest) e).Match (((CompiledExpression) expr).NamespaceManager, this))
443 XPathResultType resultType = e.ReturnType;
444 switch (resultType) {
445 case XPathResultType.Any:
446 case XPathResultType.NodeSet:
452 switch (e.EvaluatedNodeType) {
453 case XPathNodeType.Attribute:
454 case XPathNodeType.Namespace:
455 if (NodeType != e.EvaluatedNodeType)
460 XPathNodeIterator nodes;
461 nodes = this.Select (expr);
462 while (nodes.MoveNext ()) {
463 if (IsSamePosition (nodes.Current))
467 // ancestors might select this node.
469 XPathNavigator navigator = Clone ();
471 while (navigator.MoveToParent ()) {
472 nodes = navigator.Select (expr);
474 while (nodes.MoveNext ()) {
475 if (IsSamePosition (nodes.Current))
483 public abstract bool MoveTo (XPathNavigator other);
486 public virtual bool MoveToAttribute (string localName, string namespaceURI)
488 if (MoveToFirstAttribute ()) {
490 if (LocalName == localName && NamespaceURI == namespaceURI)
492 } while (MoveToNextAttribute ());
498 public virtual bool MoveToNamespace (string name)
500 if (MoveToFirstNamespace ()) {
502 if (LocalName == name)
504 } while (MoveToNextNamespace ());
511 public virtual bool MoveToFirst ()
513 if (MoveToPrevious ()) {
514 // It would be able to invoke MoveToPrevious() until the end, but this way would be much faster
523 public virtual bool MoveToFirst ()
525 return MoveToFirstImpl ();
528 public virtual void MoveToRoot ()
530 while (MoveToParent ())
534 public abstract bool MoveToAttribute (string localName, string namespaceURI);
536 public abstract bool MoveToNamespace (string name);
538 public abstract bool MoveToFirst ();
540 public abstract void MoveToRoot ();
543 internal bool MoveToFirstImpl ()
546 case XPathNodeType.Attribute:
547 case XPathNodeType.Namespace:
550 if (!MoveToParent ())
552 // Follow these 2 steps so that we can skip
553 // some types of nodes .
559 public abstract bool MoveToFirstAttribute ();
561 public abstract bool MoveToFirstChild ();
563 public bool MoveToFirstNamespace ()
565 return MoveToFirstNamespace (XPathNamespaceScope.All);
568 public abstract bool MoveToFirstNamespace (XPathNamespaceScope namespaceScope);
570 public abstract bool MoveToId (string id);
572 public abstract bool MoveToNext ();
574 public abstract bool MoveToNextAttribute ();
576 public bool MoveToNextNamespace ()
578 return MoveToNextNamespace (XPathNamespaceScope.All);
581 public abstract bool MoveToNextNamespace (XPathNamespaceScope namespaceScope);
583 public abstract bool MoveToParent ();
585 public abstract bool MoveToPrevious ();
587 public virtual XPathNodeIterator Select (string xpath)
589 return Select (Compile (xpath));
592 public virtual XPathNodeIterator Select (XPathExpression expr)
594 return Select (expr, null);
597 internal XPathNodeIterator Select (XPathExpression expr, NSResolver ctx)
599 CompiledExpression cexpr = (CompiledExpression) expr;
601 ctx = cexpr.NamespaceManager;
603 BaseIterator iter = new NullIterator (this, ctx);
604 return cexpr.EvaluateNodeSet (iter);
607 public virtual XPathNodeIterator SelectAncestors (XPathNodeType type, bool matchSelf)
609 Axes axis = (matchSelf) ? Axes.AncestorOrSelf : Axes.Ancestor;
610 return SelectTest (new NodeTypeTest (axis, type));
613 public virtual XPathNodeIterator SelectAncestors (string name, string namespaceURI, bool matchSelf)
616 throw new ArgumentNullException ("name");
617 if (namespaceURI == null)
618 throw new ArgumentNullException ("namespaceURI");
620 Axes axis = (matchSelf) ? Axes.AncestorOrSelf : Axes.Ancestor;
621 XmlQualifiedName qname = new XmlQualifiedName (name, namespaceURI);
622 return SelectTest (new NodeNameTest (axis, qname, true));
625 static IEnumerable EnumerateChildren (XPathNavigator n, XPathNodeType type)
627 if (!n.MoveToFirstChild ())
630 XPathNavigator nav = n.Clone ();
631 nav.MoveToFirstChild ();
632 XPathNavigator nav2 = null;
634 if (type == XPathNodeType.All || nav.NodeType == type) {
641 } while (nav.MoveToNext ());
644 public virtual XPathNodeIterator SelectChildren (XPathNodeType type)
647 return SelectTest (new NodeTypeTest (Axes.Child, type));
649 return new WrapperIterator (new EnumerableIterator (EnumerateChildren (this, type), 0), null);
650 // FIXME: make it work i.e. remove dependency on BaseIterator
651 // return new EnumerableIterator (EnumerateChildren (this, type), 0);
655 static IEnumerable EnumerateChildren (XPathNavigator n, string name, string ns)
657 if (!n.MoveToFirstChild ())
660 XPathNavigator nav = n.Clone ();
661 nav.MoveToFirstChild ();
662 XPathNavigator nav2 = nav.Clone ();
664 if ((name == String.Empty || nav.LocalName == name) && (ns == String.Empty || nav.NamespaceURI == ns)) {
668 } while (nav.MoveToNext ());
671 public virtual XPathNodeIterator SelectChildren (string name, string namespaceURI)
674 throw new ArgumentNullException ("name");
675 if (namespaceURI == null)
676 throw new ArgumentNullException ("namespaceURI");
679 Axes axis = Axes.Child;
680 XmlQualifiedName qname = new XmlQualifiedName (name, namespaceURI);
681 return SelectTest (new NodeNameTest (axis, qname, true));
683 return new WrapperIterator (new EnumerableIterator (EnumerateChildren (this, name, namespaceURI), 0), null);
687 public virtual XPathNodeIterator SelectDescendants (XPathNodeType type, bool matchSelf)
689 Axes axis = (matchSelf) ? Axes.DescendantOrSelf : Axes.Descendant;
690 return SelectTest (new NodeTypeTest (axis, type));
693 public virtual XPathNodeIterator SelectDescendants (string name, string namespaceURI, bool matchSelf)
696 throw new ArgumentNullException ("name");
697 if (namespaceURI == null)
698 throw new ArgumentNullException ("namespaceURI");
701 Axes axis = (matchSelf) ? Axes.DescendantOrSelf : Axes.Descendant;
702 XmlQualifiedName qname = new XmlQualifiedName (name, namespaceURI);
703 return SelectTest (new NodeNameTest (axis, qname, true));
706 internal XPathNodeIterator SelectTest (NodeTest test)
708 return test.EvaluateNodeSet (new NullIterator (this));
711 public override string ToString ()
720 public virtual bool CheckValidity (XmlSchemaSet schemas, ValidationEventHandler handler)
722 XmlReaderSettings settings = new XmlReaderSettings ();
723 settings.NameTable = NameTable;
724 settings.SetSchemas (schemas);
725 settings.ValidationEventHandler += handler;
726 settings.ValidationType = ValidationType.Schema;
728 XmlReader r = XmlReader.Create (
729 ReadSubtree (), settings);
732 } catch (XmlSchemaValidationException) {
738 public virtual XPathNavigator CreateNavigator ()
743 public virtual object Evaluate (string xpath, IXmlNamespaceResolver nsResolver)
745 return Evaluate (Compile (xpath), null, nsResolver);
748 public virtual IDictionary<string, string> GetNamespacesInScope (XmlNamespaceScope scope)
750 IDictionary<string, string> table = new Dictionary<string, string> ();
751 XPathNamespaceScope xpscope =
752 scope == XmlNamespaceScope.Local ?
753 XPathNamespaceScope.Local :
754 scope == XmlNamespaceScope.ExcludeXml ?
755 XPathNamespaceScope.ExcludeXml :
756 XPathNamespaceScope.All;
757 XPathNavigator nav = Clone ();
758 if (nav.NodeType != XPathNodeType.Element)
760 if (!nav.MoveToFirstNamespace (xpscope))
763 table.Add (nav.Name, nav.Value);
764 } while (nav.MoveToNextNamespace (xpscope));
774 virtual string LookupNamespace (string prefix)
776 XPathNavigator nav = Clone ();
777 if (nav.NodeType != XPathNodeType.Element)
779 if (nav.MoveToNamespace (prefix))
789 virtual string LookupPrefix (string namespaceUri)
791 XPathNavigator nav = Clone ();
792 if (nav.NodeType != XPathNodeType.Element)
794 if (!nav.MoveToFirstNamespace ())
797 if (nav.Value == namespaceUri)
799 } while (nav.MoveToNextNamespace ());
803 private bool MoveTo (XPathNodeIterator iter)
805 if (iter.MoveNext ()) {
806 MoveTo (iter.Current);
818 virtual bool MoveToChild (XPathNodeType type)
820 return MoveTo (SelectChildren (type));
828 virtual bool MoveToChild (string localName, string namespaceURI)
830 return MoveTo (SelectChildren (localName, namespaceURI));
838 virtual bool MoveToNext (string localName, string namespaceURI)
840 XPathNavigator nav = Clone ();
841 while (nav.MoveToNext ()) {
842 if (nav.LocalName == localName &&
843 nav.NamespaceURI == namespaceURI) {
856 virtual bool MoveToNext (XPathNodeType type)
858 XPathNavigator nav = Clone ();
859 while (nav.MoveToNext ()) {
860 if (type == XPathNodeType.All || nav.NodeType == type) {
873 virtual bool MoveToFollowing (string localName,
876 return MoveToFollowing (localName, namespaceURI, null);
884 virtual bool MoveToFollowing (string localName,
885 string namespaceURI, XPathNavigator end)
887 if (localName == null)
888 throw new ArgumentNullException ("localName");
889 if (namespaceURI == null)
890 throw new ArgumentNullException ("namespaceURI");
891 localName = NameTable.Get (localName);
892 if (localName == null)
894 namespaceURI = NameTable.Get (namespaceURI);
895 if (namespaceURI == null)
898 XPathNavigator nav = Clone ();
899 switch (nav.NodeType) {
900 case XPathNodeType.Attribute:
901 case XPathNodeType.Namespace:
906 if (!nav.MoveToFirstChild ()) {
908 if (!nav.MoveToNext ()) {
909 if (!nav.MoveToParent ())
916 if (end != null && end.IsSamePosition (nav))
918 if (object.ReferenceEquals (localName, nav.LocalName) &&
919 object.ReferenceEquals (namespaceURI, nav.NamespaceURI)) {
931 virtual bool MoveToFollowing (XPathNodeType type)
933 return MoveToFollowing (type, null);
941 virtual bool MoveToFollowing (XPathNodeType type,
944 if (type == XPathNodeType.Root)
945 return false; // will never match
946 XPathNavigator nav = Clone ();
947 switch (nav.NodeType) {
948 case XPathNodeType.Attribute:
949 case XPathNodeType.Namespace:
954 if (!nav.MoveToFirstChild ()) {
956 if (!nav.MoveToNext ()) {
957 if (!nav.MoveToParent ())
964 if (end != null && end.IsSamePosition (nav))
966 if (type == XPathNodeType.All || nav.NodeType == type) {
974 public virtual XmlReader ReadSubtree ()
977 case XPathNodeType.Element:
978 case XPathNodeType.Root:
979 return new XPathNavigatorReader (this);
981 throw new InvalidOperationException (String.Format ("NodeType {0} is not supported to read as a subtree of an XPathNavigator.", NodeType));
985 public virtual XPathNodeIterator Select (string xpath, IXmlNamespaceResolver nsResolver)
987 return Select (Compile (xpath), nsResolver);
990 public virtual XPathNavigator SelectSingleNode (string xpath)
992 return SelectSingleNode (xpath, null);
995 public virtual XPathNavigator SelectSingleNode (string xpath, IXmlNamespaceResolver nsResolver)
997 XPathExpression expr = Compile (xpath);
998 expr.SetContext (nsResolver);
999 return SelectSingleNode (expr);
1002 public virtual XPathNavigator SelectSingleNode (XPathExpression expression)
1004 XPathNodeIterator iter = Select (expression);
1005 if (iter.MoveNext ())
1006 return iter.Current;
1011 // it is not very effective code but should just work
1012 public override object ValueAs (Type type, IXmlNamespaceResolver nsResolver)
1014 return new XmlAtomicValue (Value, XmlSchemaSimpleType.XsString).ValueAs (type, nsResolver);
1017 public virtual void WriteSubtree (XmlWriter writer)
1019 writer.WriteNode (this, false);
1022 static readonly char [] escape_text_chars =
1023 new char [] {'&', '<', '>'};
1024 static readonly char [] escape_attr_chars =
1025 new char [] {'"', '&', '<', '>', '\r', '\n'};
1027 static string EscapeString (string value, bool attr)
1029 StringBuilder sb = null;
1030 char [] escape = attr ? escape_attr_chars : escape_text_chars;
1031 if (value.IndexOfAny (escape) < 0)
1033 sb = new StringBuilder (value, value.Length + 10);
1035 sb.Replace ("\"", """);
1036 sb.Replace ("<", "<");
1037 sb.Replace (">", ">");
1039 sb.Replace ("\r\n", " ");
1040 sb.Replace ("\r", " ");
1041 sb.Replace ("\n", " ");
1043 return sb.ToString ();
1046 public virtual string InnerXml {
1049 case XPathNodeType.Element:
1050 case XPathNodeType.Root:
1052 case XPathNodeType.Attribute:
1053 case XPathNodeType.Namespace:
1054 return EscapeString (Value, true);
1055 case XPathNodeType.Text:
1056 case XPathNodeType.Whitespace:
1057 case XPathNodeType.SignificantWhitespace:
1058 return String.Empty;
1059 case XPathNodeType.ProcessingInstruction:
1060 case XPathNodeType.Comment:
1064 XmlReader r = ReadSubtree ();
1066 // skip the element itself (or will reach to
1067 // EOF if other than element) unless writing
1069 int depth = r.Depth;
1070 if (NodeType != XPathNodeType.Root)
1073 depth = -1; // for Root, it should consume the entire tree, so no depth check is done.
1074 StringWriter sw = new StringWriter ();
1075 XmlWriterSettings s = new XmlWriterSettings ();
1077 s.ConformanceLevel = ConformanceLevel.Fragment;
1078 s.OmitXmlDeclaration = true;
1079 XmlWriter xtw = XmlWriter.Create (sw, s);
1080 while (!r.EOF && r.Depth > depth)
1081 xtw.WriteNode (r, false);
1082 return sw.ToString ();
1086 if (NodeType == XPathNodeType.Attribute) {
1090 AppendChild (value);
1094 public override sealed bool IsNode {
1095 get { return true; }
1098 public virtual string OuterXml {
1101 case XPathNodeType.Attribute:
1102 return String.Concat (
1104 Prefix.Length > 0 ? ":" : String.Empty,
1107 EscapeString (Value, true),
1109 case XPathNodeType.Namespace:
1110 return String.Concat (
1112 LocalName.Length > 0 ? ":" : String.Empty,
1115 EscapeString (Value, true),
1117 case XPathNodeType.Text:
1118 return EscapeString (Value, false);
1119 case XPathNodeType.Whitespace:
1120 case XPathNodeType.SignificantWhitespace:
1124 XmlWriterSettings s = new XmlWriterSettings ();
1126 s.OmitXmlDeclaration = true;
1127 s.ConformanceLevel = ConformanceLevel.Fragment;
1128 StringBuilder sb = new StringBuilder ();
1129 using (XmlWriter w = XmlWriter.Create (sb, s)) {
1132 return sb.ToString ();
1136 case XPathNodeType.Root:
1137 case XPathNodeType.Attribute:
1138 case XPathNodeType.Namespace:
1139 throw new XmlException ("Setting OuterXml Root, Attribute and Namespace is not supported.");
1143 AppendChild (value);
1144 MoveToFirstChild ();
1148 public virtual IXmlSchemaInfo SchemaInfo {
1154 public override object TypedValue {
1157 case XPathNodeType.Element:
1158 case XPathNodeType.Attribute:
1159 if (XmlType == null)
1161 XmlSchemaDatatype dt = XmlType.Datatype;
1164 return dt.ParseValue (Value, NameTable, this as IXmlNamespaceResolver);
1170 public virtual object UnderlyingObject {
1171 get { return null; }
1174 public override bool ValueAsBoolean {
1175 get { return XQueryConvert.StringToBoolean (Value); }
1178 public override DateTime ValueAsDateTime {
1179 get { return XmlConvert.ToDateTime (Value); }
1182 public override double ValueAsDouble {
1183 get { return XQueryConvert.StringToDouble (Value); }
1186 public override int ValueAsInt {
1187 get { return XQueryConvert.StringToInt (Value); }
1190 public override long ValueAsLong {
1191 get { return XQueryConvert.StringToInteger (Value); }
1194 public override Type ValueType {
1196 return SchemaInfo != null &&
1197 SchemaInfo.SchemaType != null &&
1198 SchemaInfo.SchemaType.Datatype != null ?
1199 SchemaInfo.SchemaType.Datatype.ValueType
1204 public override XmlSchemaType XmlType {
1206 if (SchemaInfo != null)
1207 return SchemaInfo.SchemaType;
1212 private XmlReader CreateFragmentReader (string fragment)
1214 XmlReaderSettings settings = new XmlReaderSettings ();
1215 settings.ConformanceLevel = ConformanceLevel.Fragment;
1216 XmlNamespaceManager nsmgr = new XmlNamespaceManager (NameTable);
1217 foreach (KeyValuePair<string,string> nss in GetNamespacesInScope (XmlNamespaceScope.All))
1218 nsmgr.AddNamespace (nss.Key, nss.Value);
1219 return XmlReader.Create (
1220 new StringReader (fragment),
1222 new XmlParserContext (NameTable, nsmgr, null, XmlSpace.None));
1225 // must override it.
1226 public virtual XmlWriter AppendChild ()
1228 throw new NotSupportedException ();
1231 public virtual void AppendChild (
1232 string xmlFragments)
1234 AppendChild (CreateFragmentReader (xmlFragments));
1237 public virtual void AppendChild (
1240 XmlWriter w = AppendChild ();
1242 w.WriteNode (reader, false);
1246 public virtual void AppendChild (
1249 AppendChild (new XPathNavigatorReader (nav));
1252 public virtual void AppendChildElement (string prefix, string name, string ns, string value)
1254 XmlWriter xw = AppendChild ();
1255 xw.WriteStartElement (prefix, name, ns);
1256 xw.WriteString (value);
1257 xw.WriteEndElement ();
1261 public virtual void CreateAttribute (string prefix, string localName, string namespaceURI, string value)
1263 using (XmlWriter w = CreateAttributes ()) {
1264 w.WriteAttributeString (prefix, localName, namespaceURI, value);
1268 // must override it.
1269 public virtual XmlWriter CreateAttributes ()
1271 throw new NotSupportedException ();
1274 // must override it.
1275 public virtual void DeleteSelf ()
1277 throw new NotSupportedException ();
1280 // must override it.
1281 public virtual void DeleteRange (XPathNavigator nav)
1283 throw new NotSupportedException ();
1286 public virtual XmlWriter ReplaceRange (XPathNavigator nav)
1288 throw new NotSupportedException ();
1291 public virtual XmlWriter InsertAfter ()
1294 case XPathNodeType.Root:
1295 case XPathNodeType.Attribute:
1296 case XPathNodeType.Namespace:
1297 throw new InvalidOperationException (String.Format ("Insertion after {0} is not allowed.", NodeType));
1299 XPathNavigator nav = Clone ();
1300 if (nav.MoveToNext ())
1301 return nav.InsertBefore ();
1302 else if (nav.MoveToParent ())
1303 return nav.AppendChild ();
1305 throw new InvalidOperationException ("Could not move to parent to insert sibling node");
1308 public virtual void InsertAfter (string xmlFragments)
1310 InsertAfter (CreateFragmentReader (xmlFragments));
1313 public virtual void InsertAfter (XmlReader reader)
1315 using (XmlWriter w = InsertAfter ()) {
1316 w.WriteNode (reader, false);
1320 public virtual void InsertAfter (XPathNavigator nav)
1322 InsertAfter (new XPathNavigatorReader (nav));
1325 public virtual XmlWriter InsertBefore ()
1327 throw new NotSupportedException ();
1330 public virtual void InsertBefore (string xmlFragments)
1332 InsertBefore (CreateFragmentReader (xmlFragments));
1335 public virtual void InsertBefore (XmlReader reader)
1337 using (XmlWriter w = InsertBefore ()) {
1338 w.WriteNode (reader, false);
1342 public virtual void InsertBefore (XPathNavigator nav)
1344 InsertBefore (new XPathNavigatorReader (nav));
1347 public virtual void InsertElementAfter (string prefix,
1348 string localName, string namespaceURI, string value)
1350 using (XmlWriter w = InsertAfter ()) {
1351 w.WriteElementString (prefix, localName, namespaceURI, value);
1355 public virtual void InsertElementBefore (string prefix,
1356 string localName, string namespaceURI, string value)
1358 using (XmlWriter w = InsertBefore ()) {
1359 w.WriteElementString (prefix, localName, namespaceURI, value);
1363 public virtual XmlWriter PrependChild ()
1365 XPathNavigator nav = Clone ();
1366 if (nav.MoveToFirstChild ())
1367 return nav.InsertBefore ();
1369 return AppendChild ();
1372 public virtual void PrependChild (string xmlFragments)
1374 PrependChild (CreateFragmentReader (xmlFragments));
1377 public virtual void PrependChild (XmlReader reader)
1379 using (XmlWriter w = PrependChild ()) {
1380 w.WriteNode (reader, false);
1384 public virtual void PrependChild (XPathNavigator nav)
1386 PrependChild (new XPathNavigatorReader (nav));
1389 public virtual void PrependChildElement (string prefix,
1390 string localName, string namespaceURI, string value)
1392 using (XmlWriter w = PrependChild ()) {
1393 w.WriteElementString (prefix, localName, namespaceURI, value);
1397 public virtual void ReplaceSelf (string xmlFragment)
1399 ReplaceSelf (CreateFragmentReader (xmlFragment));
1402 // must override it.
1403 public virtual void ReplaceSelf (XmlReader reader)
1405 throw new NotSupportedException ();
1408 public virtual void ReplaceSelf (XPathNavigator navigator)
1410 ReplaceSelf (new XPathNavigatorReader (navigator));
1413 // Dunno the exact purpose, but maybe internal editor use
1415 public virtual void SetTypedValue (object value)
1417 throw new NotSupportedException ();
1420 public virtual void SetValue (string value)
1422 throw new NotSupportedException ();
1425 private void DeleteChildren ()
1428 case XPathNodeType.Namespace:
1429 throw new InvalidOperationException ("Removing namespace node content is not supported.");
1430 case XPathNodeType.Attribute:
1432 case XPathNodeType.Text:
1433 case XPathNodeType.SignificantWhitespace:
1434 case XPathNodeType.Whitespace:
1435 case XPathNodeType.ProcessingInstruction:
1436 case XPathNodeType.Comment:
1442 XPathNavigator nav = Clone ();
1443 nav.MoveToFirstChild ();
1444 while (!nav.IsSamePosition (this))