X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FSystem.XML%2FSystem.Xml%2FXmlDocumentNavigator.cs;h=c00339be618c864f4fdb63caa188016738b53112;hb=5c9cf1e30d125d06c06fd7144484ac92fd21166f;hp=4df3fa7f169c187d0fffd0d434020710a8b04ad7;hpb=04d50fc4455e066f046cc769eca18589a304b431;p=mono.git diff --git a/mcs/class/System.XML/System.Xml/XmlDocumentNavigator.cs b/mcs/class/System.XML/System.Xml/XmlDocumentNavigator.cs index 4df3fa7f169..c00339be618 100644 --- a/mcs/class/System.XML/System.Xml/XmlDocumentNavigator.cs +++ b/mcs/class/System.XML/System.Xml/XmlDocumentNavigator.cs @@ -1,52 +1,75 @@ // // System.Xml.XmlDocumentNavigator // -// Author: +// Authors: // Jason Diamond +// Atsushi Enomoto // // (C) 2002 Jason Diamond +// (C) 2003 Atsushi Enomoto // - -using System; -using System.Collections; -using System.Xml; -using System.Xml.XPath; - -namespace System.Xml -{ - internal class XmlDocumentNavigator : XPathNavigator - { - #region Constructors - - [MonoTODO] - internal XmlDocumentNavigator(XmlNode node) - { - this.node = node; - } - - #endregion - - #region Fields - - private XmlNode node; - private IEnumerator attributesEnumerator; - - #endregion + +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; } @@ -54,6 +77,9 @@ namespace System.Xml 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; @@ -62,12 +88,35 @@ namespace System.Xml 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 || @@ -80,6 +129,9 @@ namespace System.Xml public override string Name { get { + if (NsNode != null) + return LocalName; + XPathNodeType nodeType = NodeType; bool canHaveName = nodeType == XPathNodeType.Element || @@ -91,28 +143,21 @@ namespace System.Xml } 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 { - return node.XPathNodeType; - } + 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 { @@ -121,22 +166,35 @@ namespace System.Xml case XPathNodeType.Attribute: case XPathNodeType.Comment: case XPathNodeType.ProcessingInstruction: + return node.Value; case XPathNodeType.Text: case XPathNodeType.Whitespace: 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; } } @@ -144,28 +202,51 @@ namespace System.Xml #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; } @@ -173,24 +254,39 @@ namespace System.Xml { 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; @@ -198,9 +294,17 @@ namespace System.Xml 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; } @@ -208,28 +312,75 @@ namespace System.Xml 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; } public override bool MoveToId (string id) { - XmlDocument doc; - - if (node.NodeType == XmlNodeType.Document) - doc = (XmlDocument) node; - else - doc = node.OwnerDocument; - - XmlElement eltNew = doc.GetElementById (id); + XmlElement eltNew = document.GetElementById (id); if (eltNew == null) return false; @@ -237,46 +388,177 @@ namespace System.Xml 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; @@ -284,21 +566,52 @@ namespace System.Xml 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 - } -} + } +}