2 // System.Xml.XmlDocumentNavigator
5 // Jason Diamond <jason@injektilo.org>
6 // Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
8 // (C) 2002 Jason Diamond
9 // (C) 2003 Atsushi Enomoto
13 using System.Collections;
15 using System.Xml.XPath;
19 internal class XmlDocumentNavigator : XPathNavigator, IHasXmlNode
23 internal XmlDocumentNavigator (XmlNode node)
26 nsNodeXml = document.CreateAttribute ("xmlns", "xml", Xmlns);
27 nsNodeXml.Value = XmlnsXML;
30 private XmlDocumentNavigator (XmlNode node, XmlAttribute nsNodeXml)
33 this.document = node.NodeType == XmlNodeType.Document ?
34 node as XmlDocument : node.OwnerDocument;
35 this.nsNodeXml = nsNodeXml;
41 private const string Xmlns = "http://www.w3.org/2000/xmlns/";
42 private const string XmlnsXML = "http://www.w3.org/XML/1998/namespace";
44 private XmlAttribute nsNodeXml;
46 private XmlDocument document;
47 // Current namespace node (ancestor's attribute of current node).
48 private XmlAttribute nsNode;
49 private ArrayList iteratedNsNames = new ArrayList ();
55 public override string BaseURI {
61 public override bool HasAttributes {
66 if (node.Attributes != null)
67 for (int i = 0; i < node.Attributes.Count; i++)
68 if (node.Attributes [i].NamespaceURI != Xmlns)
74 public override bool HasChildren {
79 XPathNodeType nodeType = NodeType;
80 bool canHaveChildren = nodeType == XPathNodeType.Root || nodeType == XPathNodeType.Element;
81 return canHaveChildren && node.FirstChild != null;
85 public override bool IsEmptyElement {
90 return node.NodeType == XmlNodeType.Element
91 && ((XmlElement) node).IsEmpty;
95 public XmlAttribute NsNode {
96 get { return nsNode; }
99 iteratedNsNames.Clear ();
101 iteratedNsNames.Add (value.Name);
106 public override string LocalName {
108 XmlAttribute nsNode = NsNode;
109 if (nsNode != null) {
110 if (nsNode == nsNodeXml)
113 return (nsNode.Name == "xmlns") ? String.Empty : nsNode.LocalName;
116 XPathNodeType nodeType = NodeType;
118 nodeType == XPathNodeType.Element ||
119 nodeType == XPathNodeType.Attribute ||
120 nodeType == XPathNodeType.ProcessingInstruction ||
121 nodeType == XPathNodeType.Namespace;
122 return canHaveName ? node.LocalName : String.Empty;
126 public override string Name {
131 XPathNodeType nodeType = NodeType;
133 nodeType == XPathNodeType.Element ||
134 nodeType == XPathNodeType.Attribute ||
135 nodeType == XPathNodeType.ProcessingInstruction ||
136 nodeType == XPathNodeType.Namespace;
137 return canHaveName ? node.Name : String.Empty;
141 public override string NamespaceURI {
142 get { return (NsNode != null) ? String.Empty : node.NamespaceURI; }
145 public override XmlNameTable NameTable {
147 return document.NameTable;
151 public override XPathNodeType NodeType {
152 get { return (NsNode != null) ? XPathNodeType.Namespace : node.XPathNodeType; }
155 public override string Prefix {
156 get { return (NsNode != null) ? String.Empty : node.Prefix; }
159 public override string Value {
162 case XPathNodeType.Attribute:
163 case XPathNodeType.Comment:
164 case XPathNodeType.ProcessingInstruction:
166 case XPathNodeType.Text:
167 case XPathNodeType.Whitespace:
168 case XPathNodeType.SignificantWhitespace:
169 string value = node.Value;
170 for (XmlNode n = node.NextSibling; n != null; n = n.NextSibling) {
171 switch (n.XPathNodeType) {
172 case XPathNodeType.Text:
173 case XPathNodeType.Whitespace:
174 case XPathNodeType.SignificantWhitespace:
181 case XPathNodeType.Element:
182 case XPathNodeType.Root:
183 return node.InnerText;
184 case XPathNodeType.Namespace:
185 return NsNode == nsNodeXml ? XmlnsXML : NsNode.Value;
191 public override string XmlLang {
201 private bool CheckNsNameAppearance (string name, string ns)
203 if (iteratedNsNames.Contains (name))
205 // default namespace erasure - just add name and never return this node
206 if (ns == String.Empty) {
207 iteratedNsNames.Add ("xmlns");
214 public override XPathNavigator Clone ()
216 XmlDocumentNavigator clone = new XmlDocumentNavigator (node, nsNodeXml);
217 clone.nsNode = nsNode;
218 clone.iteratedNsNames = (ArrayList) iteratedNsNames.Clone ();
222 public override string GetAttribute (string localName, string namespaceURI)
225 XmlElement el = Node as XmlElement;
226 return el != null ? el.GetAttribute (localName, namespaceURI) : String.Empty;
231 public override string GetNamespace (string name)
233 // MSDN says "String.Empty if a matching namespace
234 // node is not found or if the navigator is not
235 // positioned on an element node", but in fact it
236 // returns actual namespace for the other nodes.
237 return Node.GetNamespaceOfPrefix (name);
240 public override bool IsSamePosition (XPathNavigator other)
242 XmlDocumentNavigator otherDocumentNavigator = other as XmlDocumentNavigator;
243 if (otherDocumentNavigator != null)
244 return node == otherDocumentNavigator.node
245 && NsNode == otherDocumentNavigator.NsNode;
249 public override bool MoveTo (XPathNavigator other)
251 XmlDocumentNavigator otherDocumentNavigator = other as XmlDocumentNavigator;
252 if (otherDocumentNavigator != null) {
253 if (document == otherDocumentNavigator.document) {
254 node = otherDocumentNavigator.node;
255 NsNode = otherDocumentNavigator.NsNode;
262 public override bool MoveToAttribute (string localName, string namespaceURI)
264 if (node.Attributes != null) {
265 for (int i = 0; i < node.Attributes.Count; i++) {
266 XmlAttribute attr = node.Attributes [i];
267 if (attr.LocalName == localName
268 && attr.NamespaceURI == namespaceURI) {
278 public override bool MoveToFirst ()
280 if (NsNode == null && node.NodeType != XmlNodeType.Attribute && node.ParentNode != null) {
281 if (!MoveToParent ())
283 // Follow these 2 steps so that we can skip
284 // some types of nodes .
291 public override bool MoveToFirstAttribute ()
293 if (node.Attributes == null)
295 if (NodeType == XPathNodeType.Element) {
296 for (int i = 0; i < node.Attributes.Count; i++) {
297 XmlAttribute attr = node.Attributes [i];
298 if (attr.NamespaceURI != Xmlns) {
308 public override bool MoveToFirstChild ()
311 if (node == document) {
312 XmlNode n = node.FirstChild;
317 switch (n.NodeType) {
318 case XmlNodeType.XmlDeclaration:
319 case XmlNodeType.DocumentType:
332 node = node.FirstChild;
333 if (node.NodeType != XmlNodeType.EntityReference)
335 node = node.NextSibling;
336 } while (node != null);
345 public override bool MoveToFirstNamespace (XPathNamespaceScope namespaceScope)
347 if (NodeType != XPathNodeType.Element)
349 XmlElement el = node as XmlElement;
350 if (node.Attributes != null) {
352 for (int i = 0; i < el.Attributes.Count; i++) {
353 XmlAttribute attr = el.Attributes [i];
354 if (attr.NamespaceURI == Xmlns) {
355 if (CheckNsNameAppearance (attr.Name, attr.Value))
361 if (namespaceScope == XPathNamespaceScope.Local)
363 el = el.ParentNode as XmlElement;
364 } while (el != null);
367 if (namespaceScope == XPathNamespaceScope.All) {
368 if (CheckNsNameAppearance (nsNodeXml.Name, nsNodeXml.Value))
377 public override bool MoveToId (string id)
379 XmlElement eltNew = document.GetElementById (id);
387 public override bool MoveToNamespace (string name)
394 if (NodeType != XPathNodeType.Element)
397 XmlElement el = node as XmlElement;
398 if (node.Attributes != null) {
400 for (int i = 0; i < el.Attributes.Count; i++) {
401 XmlAttribute attr = el.Attributes [i];
402 if (attr.NamespaceURI == Xmlns && attr.Name == name) {
407 el = node.ParentNode as XmlElement;
408 } while (el != null);
413 public override bool MoveToNext ()
418 if (node.NextSibling != null) {
419 XmlNode n = node.NextSibling;
420 if (node.ParentNode != null && node.ParentNode.NodeType == XmlNodeType.Document) {
422 switch (n.NodeType) {
423 case XmlNodeType.DocumentType:
424 case XmlNodeType.XmlDeclaration:
436 if (n.NodeType != XmlNodeType.EntityReference)
451 public override bool MoveToNextAttribute ()
455 if (NodeType != XPathNodeType.Attribute)
458 // Find current attribute.
460 XmlElement owner = ((XmlAttribute) node).OwnerElement;
464 int count = owner.Attributes.Count;
465 for(; pos < count; pos++)
466 if (owner.Attributes [pos] == node)
469 return false; // Where is current attribute? Maybe removed.
471 // Find next attribute.
472 for(pos++; pos < count; pos++) {
473 if (owner.Attributes [pos].NamespaceURI != Xmlns) {
474 node = owner.Attributes [pos];
482 public override bool MoveToNextNamespace (XPathNamespaceScope namespaceScope)
484 if (NsNode == nsNodeXml)
485 // Current namespace is "xml", so there should be no more namespace nodes.
491 // Get current attribute's position.
493 XmlElement owner = ((XmlAttribute) NsNode).OwnerElement;
497 int count = owner.Attributes.Count;
498 for(; pos < count; pos++)
499 if (owner.Attributes [pos] == NsNode)
502 return false; // Where is current attribute? Maybe removed.
504 // Find next namespace from the same element as current ns node.
505 for(pos++; pos < count; pos++) {
506 if (owner.Attributes [pos].NamespaceURI == Xmlns) {
507 XmlAttribute a = owner.Attributes [pos];
508 if (CheckNsNameAppearance (a.Name, a.Value))
515 // If not found more, then find from ancestors.
516 // But if scope is Local, then it returns false here.
517 if (namespaceScope == XPathNamespaceScope.Local)
519 owner = owner.ParentNode as XmlElement;
520 while (owner != null) {
521 for (int i = 0; i < owner.Attributes.Count; i++) {
522 XmlAttribute attr = owner.Attributes [i];
523 if (attr.NamespaceURI == Xmlns) {
524 if (CheckNsNameAppearance (attr.Name, attr.Value))
530 owner = owner.ParentNode as XmlElement;
533 if (namespaceScope == XPathNamespaceScope.All) {
534 if (CheckNsNameAppearance (nsNodeXml.Name, nsNodeXml.Value))
542 public override bool MoveToParent ()
544 if (NsNode != null) {
548 else if (node.NodeType == XmlNodeType.Attribute) {
549 XmlElement ownerElement = ((XmlAttribute)node).OwnerElement;
550 if (ownerElement != null) {
555 } else if (node.ParentNode != null) {
556 node = node.ParentNode;
563 public override bool MoveToPrevious ()
568 if (node.PreviousSibling != null) {
569 if (node.ParentNode != null && node.ParentNode.NodeType == XmlNodeType.Document) {
570 XmlNode n = node.PreviousSibling;
572 switch (n.NodeType) {
573 case XmlNodeType.DocumentType:
574 case XmlNodeType.XmlDeclaration:
575 n = n.PreviousSibling;
586 node = node.PreviousSibling;
594 public override void MoveToRoot ()
596 XmlAttribute attr = node as XmlAttribute;
597 XmlNode tmp = attr != null ? attr.OwnerElement : node;
598 while (tmp.ParentNode != null)
599 tmp = tmp.ParentNode;
604 internal XmlNode Node { get { return NsNode != null ? NsNode : node; } }
606 XmlNode IHasXmlNode.GetNode ()