//
// System.Xml.XmlDocumentNavigator
//
-// Author:
+// Authors:
// Jason Diamond <jason@injektilo.org>
+// Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
//
// (C) 2002 Jason Diamond
+// (C) 2003 Atsushi Enomoto
//
-\r
-using System;\r
-using System.Collections;\r
-using System.Xml;\r
-using System.Xml.XPath;\r
-\r
-namespace System.Xml\r
-{\r
- internal class XmlDocumentNavigator : XPathNavigator\r
- {\r
- #region Constructors\r
-\r
- [MonoTODO]
- internal XmlDocumentNavigator(XmlNode node)\r
- {\r
- this.node = node;\r
- }\r
-\r
- #endregion\r
-\r
- #region Fields\r
-\r
- private XmlNode node;\r
- private IEnumerator attributesEnumerator;\r
-\r
- #endregion\r
+
+using System;
+using System.Collections;
+using System.Xml;
+using System.Xml.XPath;
+
+namespace System.Xml
+{
+ internal class XmlDocumentNavigator : XPathNavigator, IHasXmlNode
+ {
+ #region Constructors
+
+ internal XmlDocumentNavigator (XmlNode node)
+ : this (node, null)
+ {
+ nsNodeXml = document.CreateAttribute ("xmlns", "xml", Xmlns);
+ nsNodeXml.Value = XmlnsXML;
+ if (node.NodeType == XmlNodeType.Attribute && node.NamespaceURI == XmlNamespaceManager.XmlnsXmlns) {
+ nsNode = (XmlAttribute) node;
+ node = nsNode.OwnerElement;
+ }
+ }
+
+ private XmlDocumentNavigator (XmlNode node, XmlAttribute nsNodeXml)
+ {
+ this.node = node;
+ this.document = node.NodeType == XmlNodeType.Document ?
+ node as XmlDocument : node.OwnerDocument;
+ this.nsNodeXml = nsNodeXml;
+ }
+
+ #endregion
+
+ #region Fields
+ private const string Xmlns = "http://www.w3.org/2000/xmlns/";
+ private const string XmlnsXML = "http://www.w3.org/XML/1998/namespace";
+
+ private XmlAttribute nsNodeXml;
+ private XmlNode node;
+ private XmlDocument document;
+ // Current namespace node (ancestor's attribute of current node).
+ private XmlAttribute nsNode;
+ private ArrayList iteratedNsNames = new ArrayList ();
+
+ #endregion
#region Properties
- [MonoTODO]
public override string BaseURI {
get {
- throw new NotImplementedException ();
+ return node.BaseURI;
}
}
public override bool HasAttributes {
get {
+ if (NsNode != null)
+ return false;
+
if (node.Attributes != null)
- foreach (XmlAttribute attribute in node.Attributes)
- if (attribute.NamespaceURI != "http://www.w3.org/2000/xmlns/")
+ for (int i = 0; i < node.Attributes.Count; i++)
+ if (node.Attributes [i].NamespaceURI != Xmlns)
return true;
return false;
}
public override bool HasChildren {
get {
+ if (NsNode != null)
+ return false;
+
XPathNodeType nodeType = NodeType;
bool canHaveChildren = nodeType == XPathNodeType.Root || nodeType == XPathNodeType.Element;
return canHaveChildren && node.FirstChild != null;
public override bool IsEmptyElement {
get {
- return node.NodeType == XmlNodeType.Element && !HasChildren;
+ if (NsNode != null)
+ return false;
+
+ return node.NodeType == XmlNodeType.Element
+ && ((XmlElement) node).IsEmpty;
+ }
+ }
+
+ public XmlAttribute NsNode {
+ get { return nsNode; }
+ set {
+ if (value == null)
+ iteratedNsNames.Clear ();
+ else
+ iteratedNsNames.Add (value.Name);
+ nsNode = value;
}
}
public override string LocalName {
get {
+ XmlAttribute nsNode = NsNode;
+ if (nsNode != null) {
+ if (nsNode == nsNodeXml)
+ return "xml";
+ else
+ return (nsNode.Name == "xmlns") ? String.Empty : nsNode.LocalName;
+ }
+
XPathNodeType nodeType = NodeType;
bool canHaveName =
nodeType == XPathNodeType.Element ||
public override string Name {
get {
+ if (NsNode != null)
+ return LocalName;
+
XPathNodeType nodeType = NodeType;
bool canHaveName =
nodeType == XPathNodeType.Element ||
}
public override string NamespaceURI {
- get {
- return node.NamespaceURI;
- }
+ get { return (NsNode != null) ? String.Empty : node.NamespaceURI; }
}
- [MonoTODO]
public override XmlNameTable NameTable {
get {
- throw new NotImplementedException ();
+ return document.NameTable;
}
}
public override XPathNodeType NodeType {
- get {
- switch (node.NodeType) {
- case XmlNodeType.Document:
- return XPathNodeType.Root;
- case XmlNodeType.Element:
- return XPathNodeType.Element;
- case XmlNodeType.Attribute:
- return XPathNodeType.Attribute;
- case XmlNodeType.Text:
- return XPathNodeType.Text;
- case XmlNodeType.Whitespace:
- return XPathNodeType.Whitespace;
- case XmlNodeType.SignificantWhitespace:
- return XPathNodeType.SignificantWhitespace;
- case XmlNodeType.Comment:
- return XPathNodeType.Comment;
- case XmlNodeType.ProcessingInstruction:
- return XPathNodeType.ProcessingInstruction;
- }
- throw new InvalidOperationException ();
- }
+ get { return (NsNode != null) ? XPathNodeType.Namespace : node.XPathNodeType; }
}
public override string Prefix {
- get {
- return node.Prefix;
- }
+ get { return (NsNode != null) ? String.Empty : node.Prefix; }
}
public override string Value {
get {
switch (NodeType) {
case XPathNodeType.Attribute:
- return node.Value;
- case XPathNodeType.Element:
- return node.InnerText;
case XPathNodeType.Comment:
- return node.Value;
case XPathNodeType.ProcessingInstruction:
return node.Value;
case XPathNodeType.Text:
- return node.Value;
case XPathNodeType.Whitespace:
- return node.Value;
case XPathNodeType.SignificantWhitespace:
- return node.Value;
+ string value = node.Value;
+ for (XmlNode n = node.NextSibling; n != null; n = n.NextSibling) {
+ switch (n.XPathNodeType) {
+ case XPathNodeType.Text:
+ case XPathNodeType.Whitespace:
+ case XPathNodeType.SignificantWhitespace:
+ value += n.Value;
+ continue;
+ }
+ break;
+ }
+ return value;
+ case XPathNodeType.Element:
case XPathNodeType.Root:
return node.InnerText;
+ case XPathNodeType.Namespace:
+ return NsNode == nsNodeXml ? XmlnsXML : NsNode.Value;
}
return String.Empty;
}
}
- [MonoTODO]
public override string XmlLang {
get {
- throw new NotImplementedException ();
+ return node.XmlLang;
}
}
#region Methods
+ private bool CheckNsNameAppearance (string name, string ns)
+ {
+ if (iteratedNsNames.Contains (name))
+ return true;
+ // default namespace erasure - just add name and never return this node
+ if (ns == String.Empty) {
+ iteratedNsNames.Add ("xmlns");
+ return true;
+ }
+
+ return false;
+ }
+
public override XPathNavigator Clone ()
{
- return new XmlDocumentNavigator (node);
+ XmlDocumentNavigator clone = new XmlDocumentNavigator (node, nsNodeXml);
+ clone.nsNode = nsNode;
+ clone.iteratedNsNames = (ArrayList) iteratedNsNames.Clone ();
+ return clone;
}
- [MonoTODO]
public override string GetAttribute (string localName, string namespaceURI)
{
- throw new NotImplementedException ();
+ if (HasAttributes) {
+ XmlElement el = Node as XmlElement;
+ return el != null ? el.GetAttribute (localName, namespaceURI) : String.Empty;
+ }
+ return String.Empty;
}
- [MonoTODO]
public override string GetNamespace (string name)
{
- throw new NotImplementedException ();
+ // MSDN says "String.Empty if a matching namespace
+ // node is not found or if the navigator is not
+ // positioned on an element node", but in fact it
+ // returns actual namespace for the other nodes.
+ return Node.GetNamespaceOfPrefix (name);
}
public override bool IsSamePosition (XPathNavigator other)
{
XmlDocumentNavigator otherDocumentNavigator = other as XmlDocumentNavigator;
if (otherDocumentNavigator != null)
- return node == otherDocumentNavigator.node;
+ return node == otherDocumentNavigator.node
+ && NsNode == otherDocumentNavigator.NsNode;
return false;
}
{
XmlDocumentNavigator otherDocumentNavigator = other as XmlDocumentNavigator;
if (otherDocumentNavigator != null) {
- if (node.OwnerDocument == otherDocumentNavigator.node.OwnerDocument) {
+ if (document == otherDocumentNavigator.document) {
node = otherDocumentNavigator.node;
+ NsNode = otherDocumentNavigator.NsNode;
return true;
}
}
return false;
}
- [MonoTODO]
public override bool MoveToAttribute (string localName, string namespaceURI)
{
- throw new NotImplementedException ();
+ if (node.Attributes != null) {
+ for (int i = 0; i < node.Attributes.Count; i++) {
+ XmlAttribute attr = node.Attributes [i];
+ if (attr.LocalName == localName
+ && attr.NamespaceURI == namespaceURI) {
+ node = attr;
+ NsNode = null;
+ return true;
+ }
+ }
+ }
+ return false;
}
public override bool MoveToFirst ()
{
- if (node.NodeType != XmlNodeType.Attribute && node.ParentNode != null) {
- node = node.ParentNode.FirstChild;
+ if (NsNode == null && node.NodeType != XmlNodeType.Attribute && node.ParentNode != null) {
+ if (!MoveToParent ())
+ return false;
+ // Follow these 2 steps so that we can skip
+ // some types of nodes .
+ MoveToFirstChild ();
return true;
}
return false;
public override bool MoveToFirstAttribute ()
{
+ if (node.Attributes == null)
+ return false;
if (NodeType == XPathNodeType.Element) {
- attributesEnumerator = node.Attributes.GetEnumerator ();
- return MoveToNextAttribute ();
+ for (int i = 0; i < node.Attributes.Count; i++) {
+ XmlAttribute attr = node.Attributes [i];
+ if (attr.NamespaceURI != Xmlns) {
+ node = attr;
+ NsNode = null;
+ return true;
+ }
+ }
}
return false;
}
public override bool MoveToFirstChild ()
{
if (HasChildren) {
- node = node.FirstChild;
+ if (node == document) {
+ XmlNode n = node.FirstChild;
+ if (n == null)
+ return false;
+ bool loop = true;
+ do {
+ switch (n.NodeType) {
+ case XmlNodeType.XmlDeclaration:
+ case XmlNodeType.DocumentType:
+ n = n.NextSibling;
+ if (n == null)
+ return false;
+ break;
+ default:
+ loop = false;
+ break;
+ }
+ } while (loop);
+ node = n;
+ } else {
+ do {
+ node = node.FirstChild;
+ if (node.NodeType != XmlNodeType.EntityReference)
+ break;
+ node = node.NextSibling;
+ } while (node != null);
+ if (node == null)
+ return false;
+ }
return true;
}
return false;
}
- [MonoTODO]
public override bool MoveToFirstNamespace (XPathNamespaceScope namespaceScope)
{
- throw new NotImplementedException ();
+ if (NodeType != XPathNodeType.Element)
+ return false;
+ XmlElement el = node as XmlElement;
+ if (node.Attributes != null) {
+ do {
+ for (int i = 0; i < el.Attributes.Count; i++) {
+ XmlAttribute attr = el.Attributes [i];
+ if (attr.NamespaceURI == Xmlns) {
+ if (CheckNsNameAppearance (attr.Name, attr.Value))
+ continue;
+ NsNode = attr;
+ return true;
+ }
+ }
+ if (namespaceScope == XPathNamespaceScope.Local)
+ return false;
+ el = el.ParentNode as XmlElement;
+ } while (el != null);
+ }
+
+ if (namespaceScope == XPathNamespaceScope.All) {
+ if (CheckNsNameAppearance (nsNodeXml.Name, nsNodeXml.Value))
+ return false;
+ NsNode = nsNodeXml;
+ return true;
+ }
+ else
+ return false;
}
- [MonoTODO]
public override bool MoveToId (string id)
{
- throw new NotImplementedException ();
+ XmlElement eltNew = document.GetElementById (id);
+ if (eltNew == null)
+ return false;
+
+ node = eltNew;
+ return true;
}
- [MonoTODO]
public override bool MoveToNamespace (string name)
{
- throw new NotImplementedException ();
+ if (name == "xml") {
+ NsNode = nsNodeXml;
+ return true;
+ }
+
+ if (NodeType != XPathNodeType.Element)
+ return false;
+
+ XmlElement el = node as XmlElement;
+ if (node.Attributes != null) {
+ do {
+ for (int i = 0; i < el.Attributes.Count; i++) {
+ XmlAttribute attr = el.Attributes [i];
+ if (attr.NamespaceURI == Xmlns && attr.Name == name) {
+ NsNode = attr;
+ return true;
+ }
+ }
+ el = node.ParentNode as XmlElement;
+ } while (el != null);
+ }
+ return false;
}
public override bool MoveToNext ()
{
+ if (NsNode != null)
+ return false;
+
if (node.NextSibling != null) {
- node = node.NextSibling;
+ XmlNode n = node.NextSibling;
+ if (node.ParentNode != null && node.ParentNode.NodeType == XmlNodeType.Document) {
+ while (n != null) {
+ switch (n.NodeType) {
+ case XmlNodeType.DocumentType:
+ case XmlNodeType.XmlDeclaration:
+ n = n.NextSibling;
+ continue;
+ }
+ break;
+ }
+ if (n != null)
+ node = n;
+ else
+ return false;
+ } else {
+ while (n != null) {
+ if (n.NodeType != XmlNodeType.EntityReference)
+ break;
+ n = n.NextSibling;
+ }
+ if (n != null)
+ node = n;
+ else
+ return false;
+ }
return true;
}
- return false;
+ else
+ return false;
}
public override bool MoveToNextAttribute ()
{
- if (attributesEnumerator != null && attributesEnumerator.MoveNext ()) {
- node = attributesEnumerator.Current as XmlAttribute;
- return true;
+ if (node == null)
+ return false;
+ if (NodeType != XPathNodeType.Attribute)
+ return false;
+
+ // Find current attribute.
+ int pos = 0;
+ XmlElement owner = ((XmlAttribute) node).OwnerElement;
+ if (owner == null)
+ return false;
+
+ int count = owner.Attributes.Count;
+ for(; pos < count; pos++)
+ if (owner.Attributes [pos] == node)
+ break;
+ if (pos == count)
+ return false; // Where is current attribute? Maybe removed.
+
+ // Find next attribute.
+ for(pos++; pos < count; pos++) {
+ if (owner.Attributes [pos].NamespaceURI != Xmlns) {
+ node = owner.Attributes [pos];
+ NsNode = null;
+ return true;
+ }
}
return false;
}
- [MonoTODO]
public override bool MoveToNextNamespace (XPathNamespaceScope namespaceScope)
{
- throw new NotImplementedException ();
+ if (NsNode == nsNodeXml)
+ // Current namespace is "xml", so there should be no more namespace nodes.
+ return false;
+
+ if (NsNode == null)
+ return false;
+
+ // Get current attribute's position.
+ int pos = 0;
+ XmlElement owner = ((XmlAttribute) NsNode).OwnerElement;
+ if (owner == null)
+ return false;
+
+ int count = owner.Attributes.Count;
+ for(; pos < count; pos++)
+ if (owner.Attributes [pos] == NsNode)
+ break;
+ if (pos == count)
+ return false; // Where is current attribute? Maybe removed.
+
+ // Find next namespace from the same element as current ns node.
+ for(pos++; pos < count; pos++) {
+ if (owner.Attributes [pos].NamespaceURI == Xmlns) {
+ XmlAttribute a = owner.Attributes [pos];
+ if (CheckNsNameAppearance (a.Name, a.Value))
+ continue;
+ NsNode = a;
+ return true;
+ }
+ }
+
+ // If not found more, then find from ancestors.
+ // But if scope is Local, then it returns false here.
+ if (namespaceScope == XPathNamespaceScope.Local)
+ return false;
+ owner = owner.ParentNode as XmlElement;
+ while (owner != null) {
+ for (int i = 0; i < owner.Attributes.Count; i++) {
+ XmlAttribute attr = owner.Attributes [i];
+ if (attr.NamespaceURI == Xmlns) {
+ if (CheckNsNameAppearance (attr.Name, attr.Value))
+ continue;
+ NsNode = attr;
+ return true;
+ }
+ }
+ owner = owner.ParentNode as XmlElement;
+ }
+
+ if (namespaceScope == XPathNamespaceScope.All) {
+ if (CheckNsNameAppearance (nsNodeXml.Name, nsNodeXml.Value))
+ return false;
+ NsNode = nsNodeXml;
+ return true;
+ }
+ return false;
}
public override bool MoveToParent ()
{
- if (node.NodeType == XmlNodeType.Attribute) {
+ if (NsNode != null) {
+ NsNode = null;
+ return true;
+ }
+ else if (node.NodeType == XmlNodeType.Attribute) {
XmlElement ownerElement = ((XmlAttribute)node).OwnerElement;
if (ownerElement != null) {
node = ownerElement;
+ NsNode = null;
return true;
}
} else if (node.ParentNode != null) {
node = node.ParentNode;
+ NsNode = null;
return true;
}
return false;
public override bool MoveToPrevious ()
{
+ if (NsNode != null)
+ return false;
+
if (node.PreviousSibling != null) {
- node = node.PreviousSibling;
+ if (node.ParentNode != null && node.ParentNode.NodeType == XmlNodeType.Document) {
+ XmlNode n = node.PreviousSibling;
+ while (n != null) {
+ switch (n.NodeType) {
+ case XmlNodeType.DocumentType:
+ case XmlNodeType.XmlDeclaration:
+ n = n.PreviousSibling;
+ continue;
+ }
+ break;
+ }
+ if (n != null)
+ node = n;
+ else
+ return false;
+ }
+ else
+ node = node.PreviousSibling;
+
return true;
}
- return false;
+ else
+ return false;
}
public override void MoveToRoot ()
{
- if (node.NodeType != XmlNodeType.Document)
- node = node.OwnerDocument;
+ XmlAttribute attr = node as XmlAttribute;
+ XmlNode tmp = attr != null ? attr.OwnerElement : node;
+ while (tmp.ParentNode != null)
+ tmp = tmp.ParentNode;
+ node = tmp;
+ NsNode = null;
}
- internal XmlNode Node { get { return node; } }
+ internal XmlNode Node { get { return NsNode != null ? NsNode : node; } }
+
+ XmlNode IHasXmlNode.GetNode ()
+ {
+ return node;
+ }
#endregion
- }\r
-}\r
+ }
+}