diff options
Diffstat (limited to 'mcs/class/Mono.Xml.Ext/Mono.Xml.XPath/DTMXPathNavigator.cs')
-rwxr-xr-x | mcs/class/Mono.Xml.Ext/Mono.Xml.XPath/DTMXPathNavigator.cs | 630 |
1 files changed, 630 insertions, 0 deletions
diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath/DTMXPathNavigator.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath/DTMXPathNavigator.cs new file mode 100755 index 00000000000..6bd8a339a0e --- /dev/null +++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath/DTMXPathNavigator.cs @@ -0,0 +1,630 @@ +// +// Mono.Xml.XPath.DTMXPathNavigator +// +// Author: +// Atsushi Enomoto (ginga@kit.hi-ho.ne.jp) +// +// (C) 2003 Atsushi Enomoto +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +using System; +using System.Collections; +using System.Text; +using System.Xml; +using System.Xml.Schema; +using System.Xml.XPath; + +namespace Mono.Xml.XPath +{ +#if OUTSIDE_SYSTEM_XML + public +#else + internal +#endif + class DTMXPathNavigator : XPathNavigator, IXmlLineInfo + { + +#region Copy of XPathDocument + public DTMXPathNavigator (DTMXPathDocument document, + XmlNameTable nameTable, + DTMXPathLinkedNode [] nodes, + DTMXPathAttributeNode [] attributes, + DTMXPathNamespaceNode [] namespaces, + Hashtable idTable) + { + this.nodes = nodes; + this.attributes = attributes; + this.namespaces = namespaces; + this.idTable = idTable; + this.nameTable = nameTable; + + this.MoveToRoot (); + this.document = document; + } + + // Copy constructor including position informations. + public DTMXPathNavigator (DTMXPathNavigator org) + : this (org.document, org.nameTable, + org.nodes, org.attributes, org.namespaces, + org.idTable) + { + currentIsNode = org.currentIsNode; + currentIsAttr = org.currentIsAttr; + + currentNode = org.currentNode; + currentAttr = org.currentAttr; + currentNs = org.currentNs; + } + + XmlNameTable nameTable; + + // Created XPathDocument. This is used to identify the origin of the navigator. + DTMXPathDocument document; + + DTMXPathLinkedNode [] nodes;// = new DTMXPathLinkedNode [0]; + DTMXPathAttributeNode [] attributes;// = new DTMXPathAttributeNode [0]; + DTMXPathNamespaceNode [] namespaces;// = new DTMXPathNamespaceNode [0]; + + // ID table + Hashtable idTable; + +// // Key table (considered xsd:keyref for XPath 2.0) +// Hashtable keyRefTable; // [string key-name] -> idTable +// // idTable [string value] -> int nodeId +#endregion + + bool currentIsNode; + bool currentIsAttr; + + int currentNode; + int currentAttr; + int currentNs; + + StringBuilder valueBuilder; + +#region Ctor + + internal DTMXPathNavigator (XmlNameTable nt) + { + this.nameTable = nt; + } + +#endregion + +#region Properties + + public override string BaseURI { + get { return nodes [currentNode].BaseURI; } + } + + public override bool HasAttributes { + get { return currentIsNode ? nodes [currentNode].FirstAttribute != 0 : false; } + } + + public override bool HasChildren { + get { return currentIsNode ? nodes [currentNode].FirstChild != 0 : false; } + } + + public override bool IsEmptyElement { + get { return currentIsNode ? nodes [currentNode].IsEmptyElement : false; } + } + + int IXmlLineInfo.LineNumber { + get { + return currentIsAttr ? attributes [currentAttr].LineNumber : + nodes [currentNode].LineNumber; + } + } + + int IXmlLineInfo.LinePosition { + get { + return currentIsAttr ? attributes [currentAttr].LinePosition : + nodes [currentNode].LinePosition; + } + } + + public override string LocalName { + get { + if (currentIsNode) + return nodes [currentNode].LocalName; + else if (currentIsAttr) + return attributes [currentAttr].LocalName; + else + return namespaces [currentNs].Name; + } + } + + // It maybe scarcely used, so I decided to compute it always. + public override string Name { + get { + string prefix; + string localName; + if (currentIsNode) { + prefix = nodes [currentNode].Prefix; + localName = nodes [currentNode].LocalName; + } else if (currentIsAttr) { + prefix = attributes [currentAttr].Prefix; + localName = attributes [currentAttr].LocalName; + } else + return namespaces [currentNs].Name; + + if (prefix != "") + return prefix + ':' + localName; + else + return localName; + } + } + + public override string NamespaceURI { + get { + if (currentIsNode) + return nodes [currentNode].NamespaceURI; + if (currentIsAttr) + return attributes [currentAttr].NamespaceURI; + return String.Empty; + } + } + + public override XmlNameTable NameTable { + get { return nameTable; } + } + + public override XPathNodeType NodeType { + get { + if (currentIsNode) + return nodes [currentNode].NodeType; + else if (currentIsAttr) + return XPathNodeType.Attribute; + else + return XPathNodeType.Namespace; + } + } + + public override string Prefix { + get { + if (currentIsNode) + return nodes [currentNode].Prefix; + else if (currentIsAttr) + return attributes [currentAttr].Prefix; + return String.Empty; + } + } + + public override string Value { + get { + if (currentIsAttr) + return attributes [currentAttr].Value; + else if (!currentIsNode) + return namespaces [currentNs].Namespace; + + switch (nodes [currentNode].NodeType) { + case XPathNodeType.Comment: + case XPathNodeType.ProcessingInstruction: + case XPathNodeType.Text: + case XPathNodeType.Whitespace: + case XPathNodeType.SignificantWhitespace: + return nodes [currentNode].Value; + } + + // Element + if (valueBuilder == null) + valueBuilder = new StringBuilder (); + else + valueBuilder.Length = 0; + + int iter = nodes [currentNode].FirstChild; + int depth = nodes [currentNode].Depth; + while (iter < nodes.Length && nodes [iter].Depth > depth) { + switch (nodes [iter].NodeType) { + case XPathNodeType.Comment: + case XPathNodeType.ProcessingInstruction: + break; + default: + valueBuilder.Append (nodes [iter].Value); + break; + } + iter++; + } + + return valueBuilder.ToString (); + } + } + + public override string XmlLang { + get { return nodes [currentNode].XmlLang; } + } + +#endregion + +#region Methods + + public override XPathNavigator Clone () + { + return new DTMXPathNavigator (this); + } + + public override XmlNodeOrder ComparePosition (XPathNavigator nav) + { + DTMXPathNavigator another = nav as DTMXPathNavigator; + + if (another == null || another.document != this.document) + return XmlNodeOrder.Unknown; + + if (currentNode > another.currentNode) + return XmlNodeOrder.After; + else if (currentNode < another.currentNode) + return XmlNodeOrder.Before; + + // another may attr or ns, + // and this may be also attr or ns. + if (another.currentIsAttr) { + if (this.currentIsAttr) { + if (currentAttr > another.currentAttr) + return XmlNodeOrder.After; + else if (currentAttr < another.currentAttr) + return XmlNodeOrder.Before; + else + return XmlNodeOrder.Same; + } else + return XmlNodeOrder.Before; + } else if (!another.currentIsNode) { + if (!this.currentIsNode) { + if (currentNs > another.currentNs) + return XmlNodeOrder.After; + else if (currentNs < another.currentNs) + return XmlNodeOrder.Before; + else + return XmlNodeOrder.Same; + } else + return XmlNodeOrder.Before; + } else + return !another.currentIsNode ? XmlNodeOrder.Before : XmlNodeOrder.Same; + } + + private int findAttribute (string localName, string namespaceURI) + { + if (currentIsNode && nodes [currentNode].NodeType == XPathNodeType.Element) { + int cur = nodes [currentNode].FirstAttribute; + while (cur != 0) { + if (attributes [cur].LocalName == localName && attributes [cur].NamespaceURI == namespaceURI) + return cur; + cur = attributes [cur].NextAttribute; + } + } + return 0; + } + + public override string GetAttribute (string localName, + string namespaceURI) + { + int attr = findAttribute (localName, namespaceURI); + return (attr != 0) ? attributes [attr].Value : String.Empty; + } + + public override string GetNamespace (string name) + { + if (currentIsNode && nodes [currentNode].NodeType == XPathNodeType.Element) { + int nsNode = nodes [currentNode].FirstNamespace; + while (nsNode != 0) { + if (namespaces [nsNode].Name == name) + return namespaces [nsNode].Namespace; + nsNode = namespaces [nsNode].NextNamespace; + } + } + return String.Empty; + } + + bool IXmlLineInfo.HasLineInfo () + { + return true; + } + + public override bool IsDescendant (XPathNavigator nav) + { + DTMXPathNavigator another = nav as DTMXPathNavigator; + + if (another == null || another.document != this.document) + return false; + + // Maybe we can improve here more efficiently by + // comparing node indices. + if (another.currentNode == currentNode) + return !another.currentIsNode; + int tmp = nodes [another.currentNode].Parent; + while (tmp != 0) { + if (tmp == currentNode) + return true; + tmp = nodes [tmp].Parent; + } + return false; + } + + public override bool IsSamePosition (XPathNavigator other) + { + DTMXPathNavigator another = other as DTMXPathNavigator; + + if (another == null || another.document != this.document) + return false; + + if (this.currentNode != another.currentNode || + this.currentIsAttr != another.currentIsAttr || + this.currentIsNode != another.currentIsNode) + return false; + + if (currentIsAttr) + return this.currentAttr == another.currentAttr; + else if (!currentIsNode) + return this.currentNs == another.currentNs; + return true; + } + + public override bool MoveTo (XPathNavigator other) + { + DTMXPathNavigator another = other as DTMXPathNavigator; + + if (another == null || another.document != this.document) + return false; + + this.currentNode = another.currentNode; + this.currentAttr = another.currentAttr; + this.currentNs = another.currentNs; + this.currentIsNode = another.currentIsNode; + this.currentIsAttr = another.currentIsAttr; + return true; + } + + public override bool MoveToAttribute (string localName, + string namespaceURI) + { + int attr = findAttribute (localName, namespaceURI); + if (attr == 0) + return false; + + currentAttr = attr; + currentIsAttr = true; + currentIsNode = false; + return true; + } + + public override bool MoveToFirst () + { + if (currentIsAttr) + return false; + + int cur = nodes [currentNode].PreviousSibling; + if (cur == 0) + return false; + + int next = cur; + while (next != 0) { + cur = next; + next = nodes [cur].PreviousSibling; + } + currentNode = cur; + currentIsNode = true; + return true; + } + + public override bool MoveToFirstAttribute () + { + if (!currentIsNode) + return false; + + int first = nodes [currentNode].FirstAttribute; + if (first == 0) + return false; + + currentAttr = first; + currentIsAttr = true; + currentIsNode = false; + return true; + } + + public override bool MoveToFirstChild () + { + if (!currentIsNode) + return false; + + int first = nodes [currentNode].FirstChild; + if (first == 0) + return false; + + currentNode = first; + return true; + } + + private bool moveToSpecifiedNamespace (int cur, + XPathNamespaceScope namespaceScope) + { + if (cur == 0) + return false; + + if (namespaceScope == XPathNamespaceScope.Local && + namespaces [cur].DeclaredElement != currentNode) + return false; + + if (namespaceScope != XPathNamespaceScope.All + && namespaces [cur].Namespace == XmlNamespaces.XML) + return false; + + if (cur != 0) { + moveToNamespace (cur); + return true; + } + else + return false; + } + + public override bool MoveToFirstNamespace ( + XPathNamespaceScope namespaceScope) + { + if (!currentIsNode) + return false; + int cur = nodes [currentNode].FirstNamespace; + return moveToSpecifiedNamespace (cur, namespaceScope); + } + + // Note that this support is extension to XPathDocument. + // XPathDocument does not support ID reference. + public override bool MoveToId (string id) + { + if (idTable.ContainsKey (id)) { + currentNode = (int) idTable [id]; + currentIsNode = true; + currentIsAttr = false; + return true; + } + else + return false; + } + + private void moveToNamespace (int nsNode) + { + currentIsNode = currentIsAttr = false; + currentNs = nsNode; + } + + public override bool MoveToNamespace (string name) + { + int cur = nodes [currentNode].FirstNamespace; + if (cur == 0) + return false; + + while (cur != 0) { + if (namespaces [cur].Name == name) { + moveToNamespace (cur); + return true; + } + cur = namespaces [cur].NextNamespace; + } + return false; + } + + public override bool MoveToNext () + { + if (currentIsAttr) + return false; + + int next = nodes [currentNode].NextSibling; + if (next == 0) + return false; + currentNode = next; + currentIsNode = true; + return true; + } + + public override bool MoveToNextAttribute () + { + if (!currentIsAttr) + return false; + + int next = attributes [currentAttr].NextAttribute; + if (next == 0) + return false; + currentAttr = next; + return true; + } + + public override bool MoveToNextNamespace ( + XPathNamespaceScope namespaceScope) + { + if (currentIsAttr || currentIsNode) + return false; + + int cur = namespaces [currentNs].NextNamespace; + return moveToSpecifiedNamespace (cur, namespaceScope); + } + + public override bool MoveToParent () + { + if (!currentIsNode) { + currentIsNode = true; + currentIsAttr = false; + return true; + } + + int parent = nodes [currentNode].Parent; + if (parent == 0) // It is root itself. + return false; + + currentNode = parent; + return true; + } + + public override bool MoveToPrevious () + { + if (currentIsAttr) + return false; + + int previous = nodes [currentNode].PreviousSibling; + if (previous == 0) + return false; + currentNode = previous; + currentIsNode = true; + return true; + } + + public override void MoveToRoot () + { + currentNode = 1; // root is 1. + currentIsNode = true; + currentIsAttr = false; + } + +#endregion + + /* + public string DebugDump { + get { + StringBuilder sb = new StringBuilder (); + + for (int i = 0; i < namespaces.Length; i++) { + DTMXPathNamespaceNode n = namespaces [i]; + sb.AppendFormat ("{0}: {1},{2} {3}/{4}\n", i, + n.DeclaredElement, n.NextNamespace, + n.Name, n.Namespace); + } + + for (int i=0; i<this.nodes.Length; i++) { + DTMXPathLinkedNode n = nodes [i]; + sb.AppendFormat ("{0}: {1}:{2} {3} {4} {5} {6} {7}\n", new object [] {i, n.Prefix, n.LocalName, n.NamespaceURI, n.FirstNamespace, n.FirstAttribute, n.FirstChild, n.Parent}); + } + + for (int i=0; i<this.attributes.Length; i++) { + DTMXPathAttributeNode n = attributes [i]; + sb.AppendFormat ("{0}: {1}:{2} {3} {4}\n", i, n.Prefix, n.LocalName, n.NamespaceURI, n.NextAttribute); + } + + return sb.ToString (); + } + } + */ + + } + + internal class XmlNamespaces + { + public const string XML = "http://www.w3.org/XML/1998/namespace"; + public const string XMLNS = "http://www.w3.org/2000/xmlns/"; + } +} |