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 this.document = node.NodeType == XmlNodeType.Document ?
27 node as XmlDocument : node.OwnerDocument;
33 private const string Xmlns = "http://www.w3.org/2000/xmlns/";
34 private const string XmlnsXML = "http://www.w3.org/XML/1998/namespace";
37 private XmlDocument document;
38 // Current namespace node (ancestor's attribute of current node).
39 private XmlNode nsNode;
45 public override string BaseURI {
51 public override bool HasAttributes {
56 if (node.Attributes != null)
57 for (int i = 0; i < node.Attributes.Count; i++)
58 if (node.Attributes [i].NamespaceURI != Xmlns)
64 public override bool HasChildren {
69 XPathNodeType nodeType = NodeType;
70 bool canHaveChildren = nodeType == XPathNodeType.Root || nodeType == XPathNodeType.Element;
71 return canHaveChildren && node.FirstChild != null;
75 public override bool IsEmptyElement {
80 return node.NodeType == XmlNodeType.Element
81 && ((XmlElement) node).IsEmpty;
85 public override string LocalName {
88 if (nsNode == document)
91 return (nsNode.Name == "xmlns") ? String.Empty : nsNode.LocalName;
94 XPathNodeType nodeType = NodeType;
96 nodeType == XPathNodeType.Element ||
97 nodeType == XPathNodeType.Attribute ||
98 nodeType == XPathNodeType.ProcessingInstruction ||
99 nodeType == XPathNodeType.Namespace;
100 return canHaveName ? node.LocalName : String.Empty;
104 public override string Name {
109 XPathNodeType nodeType = NodeType;
111 nodeType == XPathNodeType.Element ||
112 nodeType == XPathNodeType.Attribute ||
113 nodeType == XPathNodeType.ProcessingInstruction ||
114 nodeType == XPathNodeType.Namespace;
115 return canHaveName ? node.Name : String.Empty;
119 public override string NamespaceURI {
120 get { return (nsNode != null) ? String.Empty : node.NamespaceURI; }
123 public override XmlNameTable NameTable {
125 return document.NameTable;
129 public override XPathNodeType NodeType {
130 get { return (nsNode != null) ? XPathNodeType.Namespace : node.XPathNodeType; }
133 public override string Prefix {
134 get { return (nsNode != null) ? String.Empty : node.Prefix; }
137 public override string Value {
140 case XPathNodeType.Attribute:
141 case XPathNodeType.Comment:
142 case XPathNodeType.ProcessingInstruction:
143 case XPathNodeType.Text:
144 case XPathNodeType.Whitespace:
145 case XPathNodeType.SignificantWhitespace:
147 case XPathNodeType.Element:
148 case XPathNodeType.Root:
149 return node.InnerText;
150 case XPathNodeType.Namespace:
151 return nsNode == document ? XmlnsXML : nsNode.Value;
157 public override string XmlLang {
167 public override XPathNavigator Clone ()
169 XmlDocumentNavigator clone = new XmlDocumentNavigator (node);
170 clone.nsNode = nsNode;
174 public override string GetAttribute (string localName, string namespaceURI)
177 XmlElement el = Node as XmlElement;
178 return el != null ? el.GetAttribute (localName, namespaceURI) : String.Empty;
183 public override string GetNamespace (string name)
185 // MSDN says "String.Empty if a matching namespace
186 // node is not found or if the navigator is not
187 // positioned on an element node", but in fact it
188 // returns actual namespace for the other nodes.
189 return Node.GetNamespaceOfPrefix (name);
192 public override bool IsSamePosition (XPathNavigator other)
194 XmlDocumentNavigator otherDocumentNavigator = other as XmlDocumentNavigator;
195 if (otherDocumentNavigator != null)
196 return node == otherDocumentNavigator.node
197 && nsNode == otherDocumentNavigator.nsNode;
201 public override bool MoveTo (XPathNavigator other)
203 XmlDocumentNavigator otherDocumentNavigator = other as XmlDocumentNavigator;
204 if (otherDocumentNavigator != null) {
205 if (document == otherDocumentNavigator.document) {
206 node = otherDocumentNavigator.node;
207 nsNode = otherDocumentNavigator.nsNode;
214 public override bool MoveToAttribute (string localName, string namespaceURI)
216 if (node.Attributes != null) {
217 for (int i = 0; i < node.Attributes.Count; i++) {
218 XmlAttribute attr = node.Attributes [i];
219 if (attr.LocalName == localName
220 && attr.NamespaceURI == namespaceURI) {
230 public override bool MoveToFirst ()
232 if (nsNode == null && node.NodeType != XmlNodeType.Attribute && node.ParentNode != null) {
234 // Follow these 2 steps so that we can skip
235 // some types of nodes .
242 public override bool MoveToFirstAttribute ()
244 if (node.Attributes == null)
246 if (NodeType == XPathNodeType.Element) {
247 for (int i = 0; i < node.Attributes.Count; i++) {
248 XmlAttribute attr = node.Attributes [i];
249 if (attr.NamespaceURI != Xmlns) {
259 public override bool MoveToFirstChild ()
262 if (node == document) {
263 XmlNode n = node.FirstChild;
268 switch (n.NodeType) {
269 case XmlNodeType.XmlDeclaration:
270 case XmlNodeType.DocumentType:
283 node = node.FirstChild;
284 if (node.NodeType != XmlNodeType.EntityReference)
286 node = node.NextSibling;
287 } while (node != null);
296 public override bool MoveToFirstNamespace (XPathNamespaceScope namespaceScope)
298 if (NodeType != XPathNodeType.Element)
300 XmlElement el = node as XmlElement;
301 if (node.Attributes != null) {
303 for (int i = 0; i < el.Attributes.Count; i++) {
304 XmlAttribute attr = el.Attributes [i];
305 if (attr.NamespaceURI == Xmlns) {
310 if (namespaceScope == XPathNamespaceScope.Local)
312 el = el.ParentNode as XmlElement;
313 } while (el != null);
316 if (namespaceScope == XPathNamespaceScope.All) {
324 public override bool MoveToId (string id)
326 XmlElement eltNew = document.GetElementById (id);
334 public override bool MoveToNamespace (string name)
341 if (NodeType != XPathNodeType.Element)
344 XmlElement el = node as XmlElement;
345 if (node.Attributes != null) {
347 for (int i = 0; i < el.Attributes.Count; i++) {
348 XmlAttribute attr = el.Attributes [i];
349 if (attr.NamespaceURI == Xmlns && attr.Name == name) {
354 el = node.ParentNode as XmlElement;
355 } while (el != null);
360 public override bool MoveToNext ()
365 if (node.NextSibling != null) {
366 XmlNode n = node.NextSibling;
367 if (node.ParentNode != null && node.ParentNode.NodeType == XmlNodeType.Document) {
369 switch (n.NodeType) {
370 case XmlNodeType.DocumentType:
371 case XmlNodeType.XmlDeclaration:
383 if (n.NodeType != XmlNodeType.EntityReference)
398 public override bool MoveToNextAttribute ()
402 if (NodeType != XPathNodeType.Attribute)
405 // Find current attribute.
407 XmlElement owner = ((XmlAttribute) node).OwnerElement;
411 int count = owner.Attributes.Count;
412 for(; pos < count; pos++)
413 if (owner.Attributes [pos] == node)
416 return false; // Where is current attribute? Maybe removed.
418 // Find next attribute.
419 for(pos++; pos < count; pos++) {
420 if (owner.Attributes [pos].NamespaceURI != Xmlns) {
421 node = owner.Attributes [pos];
429 public override bool MoveToNextNamespace (XPathNamespaceScope namespaceScope)
431 if (nsNode == document)
432 // Current namespace is "xml", so there should be no more namespace nodes.
438 // Get current attribute's position.
440 XmlElement owner = ((XmlAttribute) nsNode).OwnerElement;
444 int count = owner.Attributes.Count;
445 for(; pos < count; pos++)
446 if (owner.Attributes [pos] == nsNode)
449 return false; // Where is current attribute? Maybe removed.
451 // Find next namespace from the same element as current ns node.
452 for(pos++; pos < count; pos++) {
453 if (owner.Attributes [pos].NamespaceURI == Xmlns) {
454 nsNode = owner.Attributes [pos];
459 // If not found more, then find from ancestors.
460 // But if scope is Local, then it returns false here.
461 if (namespaceScope == XPathNamespaceScope.Local)
463 owner = owner.ParentNode as XmlElement;
464 while (owner != null) {
465 for (int i = 0; i < owner.Attributes.Count; i++) {
466 XmlAttribute attr = owner.Attributes [i];
467 if (attr.NamespaceURI == Xmlns) {
472 owner = owner.ParentNode as XmlElement;
475 if (namespaceScope == XPathNamespaceScope.All) {
483 public override bool MoveToParent ()
485 if (nsNode != null) {
489 else if (node.NodeType == XmlNodeType.Attribute) {
490 XmlElement ownerElement = ((XmlAttribute)node).OwnerElement;
491 if (ownerElement != null) {
496 } else if (node.ParentNode != null) {
497 node = node.ParentNode;
504 public override bool MoveToPrevious ()
509 if (node.PreviousSibling != null) {
510 if (node.ParentNode != null && node.ParentNode.NodeType == XmlNodeType.Document) {
511 XmlNode n = node.PreviousSibling;
513 switch (n.NodeType) {
514 case XmlNodeType.DocumentType:
515 case XmlNodeType.XmlDeclaration:
516 n = n.PreviousSibling;
527 node = node.PreviousSibling;
535 public override void MoveToRoot ()
537 XmlAttribute attr = node as XmlAttribute;
538 XmlNode tmp = attr != null ? attr.OwnerElement : node;
539 while (tmp.ParentNode != null)
540 tmp = tmp.ParentNode;
545 internal XmlNode Node { get { return node; } }
547 XmlNode IHasXmlNode.GetNode ()