| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630 |
- //
- // Mono.Xml.XPath.DTMXPathNavigator
- //
- // Author:
- // Atsushi Enomoto ([email protected])
- //
- // (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/";
- }
- }
|