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.
31 using System.Xml.Schema;
32 using System.Xml.XPath;
34 using XPI = System.Xml.Linq.XProcessingInstruction;
36 namespace System.Xml.Linq
38 internal class XNodeNavigator : XPathNavigator
40 static readonly XAttribute attr_ns_xml = new XAttribute (XNamespace.Xmlns.GetName ("xml"), XNamespace.Xml.NamespaceName);
44 XmlNameTable name_table;
46 public XNodeNavigator (XNode node, XmlNameTable nameTable)
49 this.name_table = nameTable;
52 public XNodeNavigator (XNodeNavigator other)
54 this.node = other.node;
55 this.attr = other.attr;
56 this.name_table = other.name_table;
59 public override string BaseURI {
60 get { return node.BaseUri ?? String.Empty; }
63 public override bool CanEdit {
67 public override bool HasAttributes {
71 XElement el = node as XElement;
74 foreach (var at in el.Attributes ())
75 if (!at.IsNamespaceDeclaration)
81 public override bool HasChildren {
85 XContainer c = node as XContainer;
86 return c != null && c.FirstNode != null;
90 public override bool IsEmptyElement {
94 XElement el = node as XElement;
95 return el != null && el.IsEmpty;
99 public override string LocalName {
102 case XPathNodeType.Namespace:
103 return attr.Name.Namespace == XNamespace.None ? String.Empty : attr.Name.LocalName;
104 case XPathNodeType.Attribute:
105 return attr.Name.LocalName;
106 case XPathNodeType.Element:
107 return ((XElement) node).Name.LocalName;
108 case XPathNodeType.ProcessingInstruction:
109 return ((XPI) node).Target;
116 public override string Name {
120 case XPathNodeType.Attribute:
123 case XPathNodeType.Element:
124 name = ((XElement) node).Name;
129 if (name.Namespace == XNamespace.None)
130 return name.LocalName;
131 XElement el = (node as XElement) ?? node.Parent;
133 return name.LocalName;
134 string prefix = el.GetPrefixOfNamespace (name.Namespace);
135 return prefix.Length > 0 ? String.Concat (prefix, ":", name.LocalName) : name.LocalName;
139 public override string NamespaceURI {
142 case XPathNodeType.ProcessingInstruction:
143 case XPathNodeType.Namespace:
145 case XPathNodeType.Attribute:
146 return attr.Name.NamespaceName;
147 case XPathNodeType.Element:
148 return ((XElement) node).Name.NamespaceName;
155 public override XmlNameTable NameTable {
156 get { return name_table; }
159 public override XPathNodeType NodeType {
162 return attr.IsNamespaceDeclaration ?
163 XPathNodeType.Namespace :
164 XPathNodeType.Attribute;
165 switch (node.NodeType) {
166 case XmlNodeType.Element:
167 return XPathNodeType.Element;
168 case XmlNodeType.Document:
169 return XPathNodeType.Root;
170 case XmlNodeType.Comment:
171 return XPathNodeType.Comment;
172 case XmlNodeType.ProcessingInstruction:
173 return XPathNodeType.ProcessingInstruction;
175 return XPathNodeType.Text;
180 public override string Prefix {
184 case XPathNodeType.ProcessingInstruction:
185 case XPathNodeType.Namespace:
187 case XPathNodeType.Attribute:
190 case XPathNodeType.Element:
191 name = ((XElement) node).Name;
196 if (name.Namespace == XNamespace.None)
198 XElement el = (node as XElement) ?? node.Parent;
201 return el.GetPrefixOfNamespace (name.Namespace);
205 public override IXmlSchemaInfo SchemaInfo {
209 public override object UnderlyingObject {
210 get { return attr != null ? (object) attr : node; }
213 public override string Value {
219 case XPathNodeType.Comment:
220 return ((XComment) node).Value;
221 case XPathNodeType.ProcessingInstruction:
222 return ((XPI) node).Data;
223 case XPathNodeType.Text:
224 string s = String.Empty;
225 for (var xn = node as XText; xn != null; xn = xn.NextNode as XText)
228 case XPathNodeType.Element:
229 case XPathNodeType.Root:
230 return GetInnerText ((XContainer) node);
236 string GetInnerText (XContainer node)
238 StringBuilder sb = null;
239 foreach (XNode n in node.Nodes ())
240 GetInnerText (n, ref sb);
241 return sb != null ? sb.ToString () : String.Empty;
244 void GetInnerText (XNode n, ref StringBuilder sb)
246 switch (n.NodeType) {
247 case XmlNodeType.Element:
248 foreach (XNode c in ((XElement) n).Nodes ())
249 GetInnerText (c, ref sb);
251 case XmlNodeType.Text:
252 case XmlNodeType.CDATA:
254 sb = new StringBuilder ();
255 sb.Append (((XText) n).Value);
260 public override XPathNavigator Clone ()
262 return new XNodeNavigator (this);
265 public override bool IsSamePosition (XPathNavigator other)
267 XNodeNavigator nav = other as XNodeNavigator;
268 if (nav == null || nav.node.Owner != node.Owner)
270 return node == nav.node && attr == nav.attr;
273 public override bool MoveTo (XPathNavigator other)
275 XNodeNavigator nav = other as XNodeNavigator;
276 if (nav == null || nav.node.Document != node.Document)
283 public override bool MoveToFirstAttribute ()
287 XElement el = node as XElement;
288 if (el == null || !el.HasAttributes)
290 foreach (XAttribute a in el.Attributes ())
291 if (!a.IsNamespaceDeclaration) {
298 public override bool MoveToFirstChild ()
302 XContainer c = node as XContainer;
303 if (c == null || c.FirstNode == null)
310 public override bool MoveToFirstNamespace (XPathNamespaceScope scope)
312 if (NodeType != XPathNodeType.Element)
314 for (XElement el = node as XElement; el != null; el = el.Parent) {
315 foreach (XAttribute a in el.Attributes ())
316 if (a.IsNamespaceDeclaration) {
320 if (scope == XPathNamespaceScope.Local)
323 if (scope != XPathNamespaceScope.All)
329 public override bool MoveToId (string id)
331 throw new NotSupportedException ("This XPathNavigator does not support IDs");
334 public override bool MoveToNext ()
336 XNode xn = node.NextNode;
338 for (; xn != null; xn = xn.NextNode)
339 if (!(xn.NextNode is XText))
348 public override bool MoveToNextAttribute ()
352 if (attr.NextAttribute == null)
354 for (XAttribute a = attr.NextAttribute; a != null; a = a.NextAttribute)
355 if (!a.IsNamespaceDeclaration) {
362 public override bool MoveToNextNamespace (XPathNamespaceScope scope)
366 for (XAttribute a = attr.NextAttribute; a != null; a = a.NextAttribute)
367 if (a.IsNamespaceDeclaration) {
372 if (scope == XPathNamespaceScope.Local)
375 if (attr == attr_ns_xml)
376 return false; // no next attribute
378 for (XElement el = ((XElement) attr.Parent).Parent; el != null; el = el.Parent) {
379 foreach (XAttribute a in el.Attributes ())
380 if (a.IsNamespaceDeclaration) {
385 if (scope != XPathNamespaceScope.All)
391 public override bool MoveToParent ()
397 if (node.Owner == null)
403 public override bool MoveToPrevious ()
405 if (node.PreviousNode == null)
407 node = node.PreviousNode;
412 public override void MoveToRoot ()
415 if (node.Document != null)
416 node = node.Document;
418 while (node.Owner != null)