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 (nav
.LocalName
== name
&& 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))