5 // Copyright 2007 Novell (http://www.novell.com)
7 // Permission is hereby granted, free of charge, to any person obtaining
8 // a copy of this software and associated documentation files (the
9 // "Software"), to deal in the Software without restriction, including
10 // without limitation the rights to use, copy, modify, merge, publish,
11 // distribute, sublicense, and/or sell copies of the Software, and to
12 // permit persons to whom the Software is furnished to do so, subject to
13 // the following conditions:
15 // The above copyright notice and this permission notice shall be
16 // included in all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System.Xml.Schema;
34 using System.Xml.XPath;
36 using XPI = System.Xml.Linq.XProcessingInstruction;
38 namespace System.Xml.Linq
40 internal class XNodeNavigator : XPathNavigator
42 static readonly XAttribute attr_ns_xml = new XAttribute (XNamespace.Xmlns.GetName ("xml"), XNamespace.Xml.NamespaceName);
46 XmlNameTable name_table;
48 public XNodeNavigator (XNode node, XmlNameTable nameTable)
51 this.name_table = nameTable;
54 public XNodeNavigator (XNodeNavigator other)
56 this.node = other.node;
57 this.attr = other.attr;
58 this.name_table = other.name_table;
61 public override string BaseURI {
62 get { return node.BaseUri ?? String.Empty; }
65 public override bool CanEdit {
69 public override bool HasAttributes {
73 XElement el = node as XElement;
76 foreach (var at in el.Attributes ())
77 if (!at.IsNamespaceDeclaration)
83 public override bool HasChildren {
87 XContainer c = node as XContainer;
88 return c != null && c.FirstNode != null;
92 public override bool IsEmptyElement {
96 XElement el = node as XElement;
97 return el != null && el.IsEmpty;
101 public override string LocalName {
104 case XPathNodeType.Namespace:
105 return attr.Name.Namespace == XNamespace.None ? String.Empty : attr.Name.LocalName;
106 case XPathNodeType.Attribute:
107 return attr.Name.LocalName;
108 case XPathNodeType.Element:
109 return ((XElement) node).Name.LocalName;
110 case XPathNodeType.ProcessingInstruction:
111 return ((XPI) node).Target;
118 public override string Name {
122 case XPathNodeType.Attribute:
125 case XPathNodeType.Element:
126 name = ((XElement) node).Name;
131 if (name.Namespace == XNamespace.None)
132 return name.LocalName;
133 XElement el = (node as XElement) ?? node.Parent;
135 return name.LocalName;
136 string prefix = el.GetPrefixOfNamespace (name.Namespace);
137 return prefix.Length > 0 ? String.Concat (prefix, ":", name.LocalName) : name.LocalName;
141 public override string NamespaceURI {
144 case XPathNodeType.ProcessingInstruction:
145 case XPathNodeType.Namespace:
147 case XPathNodeType.Attribute:
148 return attr.Name.NamespaceName;
149 case XPathNodeType.Element:
150 return ((XElement) node).Name.NamespaceName;
157 public override XmlNameTable NameTable {
158 get { return name_table; }
161 public override XPathNodeType NodeType {
164 return attr.IsNamespaceDeclaration ?
165 XPathNodeType.Namespace :
166 XPathNodeType.Attribute;
167 switch (node.NodeType) {
168 case XmlNodeType.Element:
169 return XPathNodeType.Element;
170 case XmlNodeType.Document:
171 return XPathNodeType.Root;
172 case XmlNodeType.Comment:
173 return XPathNodeType.Comment;
174 case XmlNodeType.ProcessingInstruction:
175 return XPathNodeType.ProcessingInstruction;
177 return XPathNodeType.Text;
182 public override string Prefix {
186 case XPathNodeType.ProcessingInstruction:
187 case XPathNodeType.Namespace:
189 case XPathNodeType.Attribute:
192 case XPathNodeType.Element:
193 name = ((XElement) node).Name;
198 if (name.Namespace == XNamespace.None)
200 XElement el = (node as XElement) ?? node.Parent;
203 return el.GetPrefixOfNamespace (name.Namespace);
207 public override IXmlSchemaInfo SchemaInfo {
211 public override object UnderlyingObject {
212 get { return attr != null ? (object) attr : node; }
215 public override string Value {
221 case XPathNodeType.Comment:
222 return ((XComment) node).Value;
223 case XPathNodeType.ProcessingInstruction:
224 return ((XPI) node).Data;
225 case XPathNodeType.Text:
226 string s = String.Empty;
227 for (var xn = node as XText; xn != null; xn = xn.NextNode as XText)
230 case XPathNodeType.Element:
231 case XPathNodeType.Root:
232 return GetInnerText ((XContainer) node);
238 string GetInnerText (XContainer node)
240 StringBuilder sb = null;
241 foreach (XNode n in node.Nodes ())
242 GetInnerText (n, ref sb);
243 return sb != null ? sb.ToString () : String.Empty;
246 void GetInnerText (XNode n, ref StringBuilder sb)
248 switch (n.NodeType) {
249 case XmlNodeType.Element:
250 foreach (XNode c in ((XElement) n).Nodes ())
251 GetInnerText (c, ref sb);
253 case XmlNodeType.Text:
254 case XmlNodeType.CDATA:
256 sb = new StringBuilder ();
257 sb.Append (((XText) n).Value);
262 public override XPathNavigator Clone ()
264 return new XNodeNavigator (this);
267 public override bool IsSamePosition (XPathNavigator other)
269 XNodeNavigator nav = other as XNodeNavigator;
270 if (nav == null || nav.node.Owner != node.Owner)
272 return node == nav.node && attr == nav.attr;
275 public override bool MoveTo (XPathNavigator other)
277 XNodeNavigator nav = other as XNodeNavigator;
278 if (nav == null || nav.node.Document != node.Document)
285 public override bool MoveToFirstAttribute ()
289 XElement el = node as XElement;
290 if (el == null || !el.HasAttributes)
292 foreach (XAttribute a in el.Attributes ())
293 if (!a.IsNamespaceDeclaration) {
300 public override bool MoveToFirstChild ()
304 XContainer c = node as XContainer;
305 if (c == null || c.FirstNode == null)
312 public override bool MoveToFirstNamespace (XPathNamespaceScope scope)
314 if (NodeType != XPathNodeType.Element)
316 for (XElement el = node as XElement; el != null; el = el.Parent) {
317 foreach (XAttribute a in el.Attributes ())
318 if (a.IsNamespaceDeclaration) {
322 if (scope == XPathNamespaceScope.Local)
325 if (scope != XPathNamespaceScope.All)
331 public override bool MoveToId (string id)
333 throw new NotSupportedException ("This XPathNavigator does not support IDs");
336 public override bool MoveToNext ()
338 XNode xn = node.NextNode;
340 for (; xn != null; xn = xn.NextNode)
341 if (!(xn.NextNode is XText))
350 public override bool MoveToNextAttribute ()
354 if (attr.NextAttribute == null)
356 for (XAttribute a = attr.NextAttribute; a != null; a = a.NextAttribute)
357 if (!a.IsNamespaceDeclaration) {
364 public override bool MoveToNextNamespace (XPathNamespaceScope scope)
368 for (XAttribute a = attr.NextAttribute; a != null; a = a.NextAttribute)
369 if (a.IsNamespaceDeclaration) {
374 if (scope == XPathNamespaceScope.Local)
377 if (attr == attr_ns_xml)
378 return false; // no next attribute
380 for (XElement el = ((XElement) attr.Parent).Parent; el != null; el = el.Parent) {
381 foreach (XAttribute a in el.Attributes ())
382 if (a.IsNamespaceDeclaration) {
387 if (scope != XPathNamespaceScope.All)
393 public override bool MoveToParent ()
399 if (node.Owner == null)
405 public override bool MoveToPrevious ()
407 if (node.PreviousNode == null)
409 node = node.PreviousNode;
414 public override void MoveToRoot ()
416 node = node.Document ?? node;