| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635 |
- //
- // XPathNavigatorReader.cs
- //
- // Author:
- // Atsushi Enomoto <[email protected]>
- //
- // 2003 Atsushi Enomoto. No rights reserved.
- // Copyright (C) 2004 Novell Inc.
- //
- // 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.Text;
- using System.Xml;
- using System.Xml.XPath;
- namespace Mono.Xml.XPath
- {
- internal class XPathNavigatorReader : XmlReader
- {
- public XPathNavigatorReader (XPathNavigator nav)
- {
- root = nav.Clone ();
- current = nav.Clone ();
- }
- XPathNavigator root;
- XPathNavigator current;
- bool started;
- bool closed;
- bool endElement;
- bool attributeValueConsumed;
- StringBuilder readStringBuffer = new StringBuilder ();
- StringBuilder innerXmlBuilder = new StringBuilder ();
- int depth = 0;
- int attributeCount = 0;
- bool eof;
- bool nextIsEOF;
- #region Properties
- public override XmlNodeType NodeType
- {
- get {
- if (ReadState != ReadState.Interactive)
- return XmlNodeType.None;
- if (endElement)
- return XmlNodeType.EndElement;
- if (attributeValueConsumed) {
- switch (current.NodeType) {
- case XPathNodeType.Whitespace:
- return XmlNodeType.Whitespace;
- case XPathNodeType.SignificantWhitespace:
- return XmlNodeType.SignificantWhitespace;
- default:
- return XmlNodeType.Text;
- }
- }
- switch (current.NodeType) {
- case XPathNodeType.Namespace:
- case XPathNodeType.Attribute:
- return XmlNodeType.Attribute;
- case XPathNodeType.Comment:
- return XmlNodeType.Comment;
- case XPathNodeType.Element:
- return XmlNodeType.Element;
- case XPathNodeType.ProcessingInstruction:
- return XmlNodeType.ProcessingInstruction;
- case XPathNodeType.Root:
- // It is actually Document, but in XmlReader there is no such situation to return Document.
- return XmlNodeType.None;
- case XPathNodeType.SignificantWhitespace:
- return XmlNodeType.SignificantWhitespace;
- case XPathNodeType.Text:
- return XmlNodeType.Text;
- case XPathNodeType.Whitespace:
- return XmlNodeType.Whitespace;
- default:
- throw new InvalidOperationException (String.Format ("Current XPathNavigator status is {0} which is not acceptable to XmlReader.", current.NodeType));
- }
- }
- }
- public override string Name {
- get { return eof ? String.Empty : current.Name; }
- }
- public override string LocalName {
- get { return eof ? String.Empty : current.LocalName; }
- }
- public override string NamespaceURI {
- get { return eof ? String.Empty : current.NamespaceURI; }
- }
- public override string Prefix {
- get { return eof ? String.Empty : current.Prefix; }
- }
- public override bool HasValue {
- get {
- switch (current.NodeType) {
- case XPathNodeType.Namespace:
- case XPathNodeType.Attribute:
- case XPathNodeType.Comment:
- case XPathNodeType.ProcessingInstruction:
- case XPathNodeType.SignificantWhitespace:
- case XPathNodeType.Text:
- case XPathNodeType.Whitespace:
- return true;
- }
- return false;
- }
- }
- public override int Depth {
- get {
- switch (ReadState) {
- case ReadState.EndOfFile:
- case ReadState.Initial:
- case ReadState.Closed:
- return 0;
- }
- return depth;
- }
- }
- public override string Value {
- get {
- switch (current.NodeType) {
- case XPathNodeType.Namespace:
- case XPathNodeType.Attribute:
- case XPathNodeType.Comment:
- case XPathNodeType.ProcessingInstruction:
- case XPathNodeType.SignificantWhitespace:
- case XPathNodeType.Text:
- case XPathNodeType.Whitespace:
- return current.Value;
- case XPathNodeType.Element:
- case XPathNodeType.Root:
- return String.Empty;
- default:
- throw new InvalidOperationException ("Current XPathNavigator status is {0} which is not acceptable to XmlReader.");
- }
- }
- }
- public override string BaseURI {
- get { return current.BaseURI; }
- }
- public override bool IsEmptyElement {
- get { return current.IsEmptyElement; }
- }
- // It makes no sense.
- public override bool IsDefault {
- get { return false; }
- }
- // It makes no sense.
- public override char QuoteChar {
- get { return '\"'; }
- }
- public override string XmlLang {
- get { return current.XmlLang; }
- }
- // It is meaningless.
- public override XmlSpace XmlSpace {
- get { return XmlSpace.None; }
- }
- public override int AttributeCount {
- get { return attributeCount; }
- }
- private int GetAttributeCount ()
- {
- int count = 0;
- if (current.MoveToFirstAttribute ()) {
- do {
- count++;
- } while (current.MoveToNextAttribute ());
- current.MoveToParent ();
- }
- if (current.MoveToFirstNamespace (XPathNamespaceScope.Local)) {
- do {
- count++;
- } while (current.MoveToNextNamespace (XPathNamespaceScope.Local));
- current.MoveToParent ();
- }
- return count;
- }
-
- private XPathNavigator GetAttributeNavigator (int i)
- {
- XPathNavigator backup = current.Clone ();
- try {
- switch (current.NodeType) {
- case XPathNodeType.Namespace:
- case XPathNodeType.Attribute:
- this.MoveToElement ();
- goto case XPathNodeType.Element;
- case XPathNodeType.Element:
- if (MoveToFirstAttribute ())
- if (i == 0)
- return current.Clone ();
- for (int count = 1; this.MoveToNextAttribute (); count++)
- if (count == i)
- return current.Clone ();
- break;
- }
- return null;
- } finally {
- current = backup;
- }
- }
- public override string this [int i] {
- get {
- XPathNavigator test = GetAttributeNavigator (i);
- if (test != null)
- return test.Value;
- else
- throw new ArgumentOutOfRangeException ();
- }
- }
- private void SplitName (string name, out string localName, out string ns)
- {
- localName = name;
- ns = String.Empty;
- int colon = name.IndexOf (':');
- if (colon > 0) {
- localName = name.Substring (colon + 1, name.Length - colon - 1);
- ns = this.LookupNamespace (name.Substring (0, colon));
- }
- }
- public override string this [string name] {
- get {
- string localName;
- string ns;
- SplitName (name, out localName, out ns);
- return this [localName, ns];
- }
- }
- public override string this [string localName, string namespaceURI] {
- get {
- string v = current.GetAttribute (localName, namespaceURI);
- if (v != String.Empty)
- return v;
- XPathNavigator tmp = current.Clone ();
- return tmp.MoveToAttribute (localName, namespaceURI) ? String.Empty : null;
- }
- }
- public override bool EOF {
- get {
- return eof || ReadState == ReadState.EndOfFile;
- }
- }
- public override ReadState ReadState {
- get {
- if (closed)
- return ReadState.Closed;
- else if (!started)
- return ReadState.Initial;
- else if (eof)
- return ReadState.EndOfFile;
- return ReadState.Interactive;
- }
- }
- public override XmlNameTable NameTable {
- get { return current.NameTable; }
- }
- #endregion
- #region Methods
- public override string GetAttribute (string name)
- {
- string localName;
- string ns;
- SplitName (name, out localName, out ns);
- return this [localName, ns];
- }
- public override string GetAttribute (string localName, string namespaceURI)
- {
- return this [localName, namespaceURI];
- }
- public override string GetAttribute (int i)
- {
- return this [i];
- }
- private bool CheckAttributeMove (bool b)
- {
- if (b)
- attributeValueConsumed = false;
- return b;
- }
- public override bool MoveToAttribute (string name)
- {
- string localName;
- string ns;
- SplitName (name, out localName, out ns);
- return CheckAttributeMove (MoveToAttribute (localName, ns));
- }
- public override bool MoveToAttribute (string localName, string namespaceURI)
- {
- XPathNavigator backup = null;
- switch (current.NodeType) {
- case XPathNodeType.Attribute:
- backup = current.Clone ();
- this.MoveToElement ();
- goto case XPathNodeType.Element;
- case XPathNodeType.Element:
- while (MoveToNextAttribute ())
- if (current.LocalName == localName && current.NamespaceURI == namespaceURI) {
- attributeValueConsumed = false;
- return true;
- }
- break;
- }
- if (backup != null)
- current = backup;
- return false;
- }
- public override void MoveToAttribute (int i)
- {
- XPathNavigator test = GetAttributeNavigator (i);
- if (test == null)
- throw new ArgumentOutOfRangeException ();
- else {
- attributeValueConsumed = false;
- current = test;
- }
- }
- public override bool MoveToFirstAttribute ()
- {
- bool b = CheckAttributeMove (current.MoveToFirstNamespace (XPathNamespaceScope.Local));
- if (b)
- return true;
- return CheckAttributeMove (current.MoveToFirstAttribute ());
- }
- public override bool MoveToNextAttribute ()
- {
- if (current.NodeType != XPathNodeType.Attribute) {
- bool b = CheckAttributeMove (current.MoveToNextNamespace (XPathNamespaceScope.Local));
- if (b)
- return true;
- }
- return CheckAttributeMove (current.MoveToNextAttribute ());
- }
- public override bool MoveToElement ()
- {
- if (current.NodeType == XPathNodeType.Attribute ||
- current.NodeType == XPathNodeType.Namespace) {
- attributeValueConsumed = false;
- return current.MoveToParent ();
- }
- return false;
- }
- public override void Close ()
- {
- closed = true;
- eof = true;
- }
- public override bool Read ()
- {
- switch (ReadState) {
- case ReadState.EndOfFile:
- case ReadState.Closed:
- case ReadState.Error:
- return false;
- case ReadState.Initial:
- started = true;
- if (current.NodeType != XPathNodeType.Root)
- return true;
- break;
- }
- if (nextIsEOF) {
- nextIsEOF = false;
- eof = true;
- return false;
- }
- MoveToElement ();
- if (endElement || current.MoveToFirstChild () == false) {
- if (current.MoveToNext () == false) {
- if (current.IsSamePosition (root)) { // It should happen only when the root node was empty.
- eof = true;
- return false;
- }
- current.MoveToParent ();
- depth--;
- endElement = (current.NodeType == XPathNodeType.Element);
- if (current.IsSamePosition (root)) {
- if (current.NodeType == XPathNodeType.Element)
- nextIsEOF = true;
- else {
- endElement = false;
- eof = true;
- return false;
- }
- }
- } else
- endElement = false;
- }
- else if (!endElement)
- depth++;
- attributeCount = GetAttributeCount ();
- return true;
- }
- public override string ReadString ()
- {
- readStringBuffer.Length = 0;
- switch (NodeType) {
- default:
- return String.Empty;
- case XmlNodeType.Element:
- if (IsEmptyElement)
- return String.Empty;
- do {
- Read ();
- switch (NodeType) {
- case XmlNodeType.Text:
- case XmlNodeType.CDATA:
- case XmlNodeType.Whitespace:
- case XmlNodeType.SignificantWhitespace:
- readStringBuffer.Append (Value);
- continue;
- }
- break;
- } while (true);
- break;
- case XmlNodeType.Text:
- case XmlNodeType.CDATA:
- case XmlNodeType.Whitespace:
- case XmlNodeType.SignificantWhitespace:
- do {
- switch (NodeType) {
- case XmlNodeType.Text:
- case XmlNodeType.CDATA:
- case XmlNodeType.Whitespace:
- case XmlNodeType.SignificantWhitespace:
- readStringBuffer.Append (Value);
- Read ();
- continue;
- }
- break;
- } while (true);
- break;
- }
- string ret = readStringBuffer.ToString ();
- readStringBuffer.Length = 0;
- return ret;
- }
- #if NET_1_1
- #else
- public override string ReadInnerXml ()
- {
- if (ReadState != ReadState.Interactive)
- return String.Empty;
- switch (NodeType) {
- case XmlNodeType.Attribute:
- return Value;
- case XmlNodeType.Element:
- if (IsEmptyElement)
- return String.Empty;
- int startDepth = Depth;
- innerXmlBuilder.Length = 0;
- bool loop = true;
- do {
- Read ();
- if (NodeType ==XmlNodeType.None)
- throw new InvalidOperationException ("unexpected end of xml.");
- else if (NodeType == XmlNodeType.EndElement && Depth == startDepth) {
- loop = false;
- Read ();
- }
- else
- innerXmlBuilder.Append (GetCurrentTagMarkup ());
- } while (loop);
- string xml = innerXmlBuilder.ToString ();
- innerXmlBuilder.Length = 0;
- return xml;
- case XmlNodeType.None:
- // MS document is incorrect. Seems not to progress.
- return String.Empty;
- default:
- Read ();
- return String.Empty;
- }
- }
-
- StringBuilder atts = new StringBuilder ();
- private string GetCurrentTagMarkup ()
- {
- switch (NodeType) {
- case XmlNodeType.CDATA:
- return String.Format ("<![CDATA[{0}]]>", Value.Replace ("]]>", "]]>"));
- case XmlNodeType.Text:
- return Value.Replace ("<", "<");
- case XmlNodeType.Comment:
- return String.Format ("<!--{0}-->", Value);
- case XmlNodeType.SignificantWhitespace:
- case XmlNodeType.Whitespace:
- return Value;
- case XmlNodeType.EndElement:
- return String.Format ("</{0}>", Name);
- }
- bool isEmpty = IsEmptyElement;
- string name = Name;
- atts.Length = 0;
- XPathNavigator temp = current.Clone ();
- while (temp.MoveToNextAttribute ())
- atts.AppendFormat (" {0}='{1}'", temp.Name, temp.Value.Replace ("'", "'"));
- if (!IsEmptyElement)
- return String.Format ("<{0}{1}>", name, atts);
- else
- return String.Format ("<{0}{1} />", name, atts);
- }
- // Arranged copy of XmlTextReader.ReadOuterXml()
- public override string ReadOuterXml ()
- {
- if (ReadState != ReadState.Interactive)
- return String.Empty;
- switch (NodeType) {
- case XmlNodeType.Attribute:
- // strictly incompatible with MS... (it holds spaces attribute between name, value and "=" char (very trivial).
- return String.Format ("{0}={1}{2}{1}", Name, QuoteChar, ReadInnerXml ());
- case XmlNodeType.Element:
- bool isEmpty = IsEmptyElement;
- string name = Name;
- StringBuilder atts = new StringBuilder ();
- XPathNavigator temp = current.Clone ();
- while (temp.MoveToNextAttribute ())
- atts.AppendFormat (" {0}='{1}'", temp.Name, temp.Value.Replace ("'", "'"));
- if (!isEmpty)
- return String.Format ("{0}{1}</{2}>", GetCurrentTagMarkup (), atts, ReadInnerXml (), name);
- else
- return String.Format ("{0}", GetCurrentTagMarkup ());
- case XmlNodeType.None:
- // MS document is incorrect. Seems not to progress.
- return String.Empty;
- default:
- Read ();
- return String.Empty;
- }
- }
- #endif
- public override string LookupNamespace (string prefix)
- {
- XPathNavigator backup = current.Clone ();
- try {
- this.MoveToElement ();
- if (current.MoveToFirstNamespace ()) {
- do {
- if (current.LocalName == prefix)
- return current.Value;
- } while (current.MoveToNextNamespace ());
- }
- return null;
- } finally {
- current = backup;
- }
- }
- // It does not support entity resolution.
- public override void ResolveEntity ()
- {
- throw new InvalidOperationException ();
- }
- public override bool ReadAttributeValue () {
- if (NodeType != XmlNodeType.Attribute)
- return false;
- if (attributeValueConsumed)
- return false;
- attributeValueConsumed = true;
- return true;
- }
- #endregion
- }
- }
|