// // XmlReader.cs // // Authors: // Jason Diamond (jason@injektilo.org) // Gonzalo Paniagua Javier (gonzalo@ximian.com) // Atsushi Enomoto (ginga@kit.hi-ho.ne.jp) // // (C) 2001, 2002 Jason Diamond http://injektilo.org/ // (c) 2002 Ximian, Inc. (http://www.ximian.com) // (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.Collections; using System.Diagnostics; using System.IO; using System.Text; #if !MOONLIGHT using System.Xml.Schema; // only required for NET_2_0 (SchemaInfo) using System.Xml.Serialization; // only required for NET_2_0 (SchemaInfo) using Mono.Xml.Schema; // only required for NET_2_0 #endif using Mono.Xml; // only required for NET_2_0 namespace System.Xml { #if NET_2_0 public abstract class XmlReader : IDisposable #else public abstract class XmlReader #endif { private StringBuilder readStringBuffer; private XmlReaderBinarySupport binary; #if NET_2_0 private XmlReaderSettings settings; #endif #region Constructor protected XmlReader () { } #endregion #region Properties public abstract int AttributeCount { get; } public abstract string BaseURI { get; } internal XmlReaderBinarySupport Binary { get { return binary; } } internal XmlReaderBinarySupport.CharGetter BinaryCharGetter { get { return binary != null ? binary.Getter : null; } set { if (binary == null) binary = new XmlReaderBinarySupport (this); binary.Getter = value; } } #if NET_2_0 // To enable it internally in sys.xml, just insert these // two lines into Read(): // // #if NET_2_0 // if (Binary != null) // Binary.Reset (); // #endif // public virtual bool CanReadBinaryContent { get { return false; } } public virtual bool CanReadValueChunk { get { return false; } } #else internal virtual bool CanReadBinaryContent { get { return false; } } internal virtual bool CanReadValueChunk { get { return false; } } #endif public virtual bool CanResolveEntity { get { return false; } } public abstract int Depth { get; } public abstract bool EOF { get; } public virtual bool HasAttributes { get { return AttributeCount > 0; } } public abstract bool HasValue { get; } public abstract bool IsEmptyElement { get; } #if NET_2_0 public virtual bool IsDefault { get { return false; } } public virtual string this [int i] { get { return GetAttribute (i); } } public virtual string this [string name] { get { return GetAttribute (name); } } public virtual string this [string name, string namespaceURI] { get { return GetAttribute (name, namespaceURI); } } #else public abstract bool IsDefault { get; } public abstract string this [int i] { get; } public abstract string this [string name] { get; } public abstract string this [string localName, string namespaceName] { get; } #endif public abstract string LocalName { get; } #if NET_2_0 public virtual string Name { get { return Prefix.Length > 0 ? String.Concat (Prefix, ":", LocalName) : LocalName; } } #else public abstract string Name { get; } #endif public abstract string NamespaceURI { get; } public abstract XmlNameTable NameTable { get; } public abstract XmlNodeType NodeType { get; } public abstract string Prefix { get; } #if NET_2_0 public virtual char QuoteChar { get { return '\"'; } } #else public abstract char QuoteChar { get; } #endif public abstract ReadState ReadState { get; } #if NET_2_0 #if !MOONLIGHT public virtual IXmlSchemaInfo SchemaInfo { get { return null; } } #endif public virtual XmlReaderSettings Settings { get { return settings; } } #endif public abstract string Value { get; } #if NET_2_0 public virtual string XmlLang { get { return String.Empty; } } public virtual XmlSpace XmlSpace { get { return XmlSpace.None; } } #else public abstract string XmlLang { get; } public abstract XmlSpace XmlSpace { get; } #endif #endregion #region Methods public abstract void Close (); #if NET_2_0 private static XmlNameTable PopulateNameTable ( XmlReaderSettings settings) { XmlNameTable nameTable = settings.NameTable; if (nameTable == null) nameTable = new NameTable (); return nameTable; } private static XmlParserContext PopulateParserContext ( XmlReaderSettings settings, string baseUri) { XmlNameTable nt = PopulateNameTable (settings); return new XmlParserContext (nt, new XmlNamespaceManager (nt), null, null, null, null, baseUri, null, XmlSpace.None, null); } private static XmlNodeType GetNodeType ( XmlReaderSettings settings) { ConformanceLevel level = settings != null ? settings.ConformanceLevel : ConformanceLevel.Auto; return level == ConformanceLevel.Fragment ? XmlNodeType.Element : XmlNodeType.Document; } public static XmlReader Create (Stream stream) { return Create (stream, null); } public static XmlReader Create (string url) { return Create (url, null); } public static XmlReader Create (TextReader reader) { return Create (reader, null); } public static XmlReader Create (string url, XmlReaderSettings settings) { return Create (url, settings, null); } public static XmlReader Create (Stream stream, XmlReaderSettings settings) { return Create (stream, settings, String.Empty); } public static XmlReader Create (TextReader reader, XmlReaderSettings settings) { return Create (reader, settings, String.Empty); } static XmlReaderSettings PopulateSettings (XmlReaderSettings src) { if (src == null) return new XmlReaderSettings (); else return src.Clone (); } public static XmlReader Create (Stream stream, XmlReaderSettings settings, string baseUri) { settings = PopulateSettings (settings); return Create (stream, settings, PopulateParserContext (settings, baseUri)); } public static XmlReader Create (TextReader reader, XmlReaderSettings settings, string baseUri) { settings = PopulateSettings (settings); return Create (reader, settings, PopulateParserContext (settings, baseUri)); } public static XmlReader Create (XmlReader reader, XmlReaderSettings settings) { settings = PopulateSettings (settings); XmlReader r = CreateFilteredXmlReader (reader, settings); r.settings = settings; return r; } public static XmlReader Create (string url, XmlReaderSettings settings, XmlParserContext context) { settings = PopulateSettings (settings); bool closeInputBak = settings.CloseInput; try { settings.CloseInput = true; // forced. See XmlReaderCommonTests.CreateFromUrlClose(). if (context == null) context = PopulateParserContext (settings, url); XmlTextReader xtr = new XmlTextReader (false, settings.XmlResolver, url, GetNodeType (settings), context); XmlReader ret = CreateCustomizedTextReader (xtr, settings); return ret; } finally { settings.CloseInput = closeInputBak; } } public static XmlReader Create (Stream stream, XmlReaderSettings settings, XmlParserContext context) { settings = PopulateSettings (settings); if (context == null) context = PopulateParserContext (settings, String.Empty); return CreateCustomizedTextReader (new XmlTextReader (stream, GetNodeType (settings), context), settings); } public static XmlReader Create (TextReader reader, XmlReaderSettings settings, XmlParserContext context) { settings = PopulateSettings (settings); if (context == null) context = PopulateParserContext (settings, String.Empty); return CreateCustomizedTextReader (new XmlTextReader (context.BaseURI, reader, GetNodeType (settings), context), settings); } private static XmlReader CreateCustomizedTextReader (XmlTextReader reader, XmlReaderSettings settings) { reader.XmlResolver = settings.XmlResolver; // Normalization is set true by default. reader.Normalization = true; reader.EntityHandling = EntityHandling.ExpandEntities; if (settings.ProhibitDtd) reader.ProhibitDtd = true; if (!settings.CheckCharacters) reader.CharacterChecking = false; // I guess it might be changed in 2.0 RTM to set true // as default, or just disappear. It goes against // XmlTextReader's default usage and users will have // to close input manually (that's annoying). Moreover, // MS XmlTextReader consumes text input more than // actually read and users can acquire those extra // consumption by GetRemainder() that returns different // TextReader. reader.CloseInput = settings.CloseInput; // I would like to support it in detail later; // MSDN description looks source of confusion. We don't // need examples, but precise list of how it works. reader.Conformance = settings.ConformanceLevel; reader.AdjustLineInfoOffset (settings.LineNumberOffset, settings.LinePositionOffset); if (settings.NameTable != null) reader.SetNameTable (settings.NameTable); XmlReader r = CreateFilteredXmlReader (reader, settings); r.settings = settings; return r; } private static XmlReader CreateFilteredXmlReader (XmlReader reader, XmlReaderSettings settings) { ConformanceLevel conf = ConformanceLevel.Auto; if (reader is XmlTextReader) conf = ((XmlTextReader) reader).Conformance; else if (reader.Settings != null) conf = reader.Settings.ConformanceLevel; else conf = settings.ConformanceLevel; if (settings.ConformanceLevel != ConformanceLevel.Auto && conf != settings.ConformanceLevel) throw new InvalidOperationException (String.Format ("ConformanceLevel cannot be overwritten by a wrapping XmlReader. The source reader has {0}, while {1} is specified.", conf, settings.ConformanceLevel)); settings.ConformanceLevel = conf; reader = CreateValidatingXmlReader (reader, settings); if ( settings.IgnoreComments || settings.IgnoreProcessingInstructions || settings.IgnoreWhitespace) return new XmlFilterReader (reader, settings); else { reader.settings = settings; return reader; } } private static XmlReader CreateValidatingXmlReader (XmlReader reader, XmlReaderSettings settings) { #if MOONLIGHT return reader; #else XmlValidatingReader xvr = null; switch (settings.ValidationType) { // Auto and XDR are obsoleted in 2.0 and therefore ignored. default: return reader; case ValidationType.DTD: xvr = new XmlValidatingReader (reader); xvr.XmlResolver = settings.XmlResolver; xvr.ValidationType = ValidationType.DTD; break; case ValidationType.Schema: return new XmlSchemaValidatingReader (reader, settings); } // Actually I don't think they are treated in DTD validation though... if ((settings.ValidationFlags & XmlSchemaValidationFlags.ProcessIdentityConstraints) == 0) throw new NotImplementedException (); //if ((settings.ValidationFlags & XmlSchemaValidationFlags.ProcessInlineSchema) != 0) // throw new NotImplementedException (); //if ((settings.ValidationFlags & XmlSchemaValidationFlags.ProcessSchemaLocation) != 0) // throw new NotImplementedException (); //if ((settings.ValidationFlags & XmlSchemaValidationFlags.ReportValidationWarnings) == 0) // throw new NotImplementedException (); return xvr != null ? xvr : reader; #endif } void IDisposable.Dispose () { Dispose (false); } protected virtual void Dispose (bool disposing) { if (ReadState != ReadState.Closed) Close (); } #endif public abstract string GetAttribute (int i); public abstract string GetAttribute (string name); public abstract string GetAttribute ( string localName, string namespaceName); public static bool IsName (string s) { return s != null && XmlChar.IsName (s); } public static bool IsNameToken (string s) { return s != null && XmlChar.IsNmToken (s); } public virtual bool IsStartElement () { return (MoveToContent () == XmlNodeType.Element); } public virtual bool IsStartElement (string name) { if (!IsStartElement ()) return false; return (Name == name); } public virtual bool IsStartElement (string localName, string namespaceName) { if (!IsStartElement ()) return false; return (LocalName == localName && NamespaceURI == namespaceName); } public abstract string LookupNamespace (string prefix); #if NET_2_0 public virtual void MoveToAttribute (int i) { if (i >= AttributeCount) throw new ArgumentOutOfRangeException (); MoveToFirstAttribute (); for (int a = 0; a < i; a++) MoveToNextAttribute (); } #else public abstract void MoveToAttribute (int i); #endif public abstract bool MoveToAttribute (string name); public abstract bool MoveToAttribute ( string localName, string namespaceName); private bool IsContent (XmlNodeType nodeType) { /* MS doc says: * (non-white space text, CDATA, Element, EndElement, EntityReference, or EndEntity) */ switch (nodeType) { case XmlNodeType.Text: return true; case XmlNodeType.CDATA: return true; case XmlNodeType.Element: return true; case XmlNodeType.EndElement: return true; case XmlNodeType.EntityReference: return true; case XmlNodeType.EndEntity: return true; } return false; } public virtual XmlNodeType MoveToContent () { switch (ReadState) { case ReadState.Initial: case ReadState.Interactive: break; default: return NodeType; } if (NodeType == XmlNodeType.Attribute) MoveToElement (); do { if (IsContent (NodeType)) return NodeType; Read (); } while (!EOF); return XmlNodeType.None; } public abstract bool MoveToElement (); public abstract bool MoveToFirstAttribute (); public abstract bool MoveToNextAttribute (); public abstract bool Read (); public abstract bool ReadAttributeValue (); public virtual string ReadElementString () { if (MoveToContent () != XmlNodeType.Element) { string error = String.Format ("'{0}' is an invalid node type.", NodeType.ToString ()); throw XmlError (error); } string result = String.Empty; if (!IsEmptyElement) { Read (); result = ReadString (); if (NodeType != XmlNodeType.EndElement) { string error = String.Format ("'{0}' is an invalid node type.", NodeType.ToString ()); throw XmlError (error); } } Read (); return result; } public virtual string ReadElementString (string name) { if (MoveToContent () != XmlNodeType.Element) { string error = String.Format ("'{0}' is an invalid node type.", NodeType.ToString ()); throw XmlError (error); } if (name != Name) { string error = String.Format ("The {0} tag from namespace {1} is expected.", Name, NamespaceURI); throw XmlError (error); } string result = String.Empty; if (!IsEmptyElement) { Read (); result = ReadString (); if (NodeType != XmlNodeType.EndElement) { string error = String.Format ("'{0}' is an invalid node type.", NodeType.ToString ()); throw XmlError (error); } } Read (); return result; } public virtual string ReadElementString (string localName, string namespaceName) { if (MoveToContent () != XmlNodeType.Element) { string error = String.Format ("'{0}' is an invalid node type.", NodeType.ToString ()); throw XmlError (error); } if (localName != LocalName || NamespaceURI != namespaceName) { string error = String.Format ("The {0} tag from namespace {1} is expected.", LocalName, NamespaceURI); throw XmlError (error); } string result = String.Empty; if (!IsEmptyElement) { Read (); result = ReadString (); if (NodeType != XmlNodeType.EndElement) { string error = String.Format ("'{0}' is an invalid node type.", NodeType.ToString ()); throw XmlError (error); } } Read (); return result; } public virtual void ReadEndElement () { if (MoveToContent () != XmlNodeType.EndElement) { string error = String.Format ("'{0}' is an invalid node type.", NodeType.ToString ()); throw XmlError (error); } Read (); } public virtual string ReadInnerXml () { if (ReadState != ReadState.Interactive || NodeType == XmlNodeType.EndElement) return String.Empty; if (IsEmptyElement) { Read (); return String.Empty; } StringWriter sw = new StringWriter (); XmlTextWriter xtw = new XmlTextWriter (sw); if (NodeType == XmlNodeType.Element) { int startDepth = Depth; Read (); while (startDepth < Depth) { if (ReadState != ReadState.Interactive) throw XmlError ("Unexpected end of the XML reader."); xtw.WriteNode (this, false); } // reader is now end element, then proceed once more. Read (); } else xtw.WriteNode (this, false); return sw.ToString (); } public virtual string ReadOuterXml () { if (ReadState != ReadState.Interactive || NodeType == XmlNodeType.EndElement) return String.Empty; switch (NodeType) { case XmlNodeType.Element: case XmlNodeType.Attribute: StringWriter sw = new StringWriter (); XmlTextWriter xtw = new XmlTextWriter (sw); xtw.WriteNode (this, false); return sw.ToString (); default: Skip (); return String.Empty; } } public virtual void ReadStartElement () { if (MoveToContent () != XmlNodeType.Element) { string error = String.Format ("'{0}' is an invalid node type.", NodeType.ToString ()); throw XmlError (error); } Read (); } public virtual void ReadStartElement (string name) { if (MoveToContent () != XmlNodeType.Element) { string error = String.Format ("'{0}' is an invalid node type.", NodeType.ToString ()); throw XmlError (error); } if (name != Name) { string error = String.Format ("The {0} tag from namespace {1} is expected.", Name, NamespaceURI); throw XmlError (error); } Read (); } public virtual void ReadStartElement (string localName, string namespaceName) { if (MoveToContent () != XmlNodeType.Element) { string error = String.Format ("'{0}' is an invalid node type.", NodeType.ToString ()); throw XmlError (error); } if (localName != LocalName || NamespaceURI != namespaceName) { string error = String.Format ("Expecting {0} tag from namespace {1}, got {2} and {3} instead", localName, namespaceName, LocalName, NamespaceURI); throw XmlError (error); } Read (); } public virtual string ReadString () { if (readStringBuffer == null) readStringBuffer = new StringBuilder (); readStringBuffer.Length = 0; MoveToElement (); 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_2_0 public virtual Type ValueType { get { return typeof (string); } } public virtual bool ReadToDescendant (string name) { if (ReadState == ReadState.Initial) { MoveToContent (); if (IsStartElement (name)) return true; } if (NodeType != XmlNodeType.Element || IsEmptyElement) return false; int depth = Depth; for (Read (); depth < Depth; Read ()) if (NodeType == XmlNodeType.Element && name == Name) return true; return false; } public virtual bool ReadToDescendant (string localName, string namespaceURI) { if (ReadState == ReadState.Initial) { MoveToContent (); if (IsStartElement (localName, namespaceURI)) return true; } if (NodeType != XmlNodeType.Element || IsEmptyElement) return false; int depth = Depth; for (Read (); depth < Depth; Read ()) if (NodeType == XmlNodeType.Element && localName == LocalName && namespaceURI == NamespaceURI) return true; return false; } public virtual bool ReadToFollowing (string name) { while (Read ()) if (NodeType == XmlNodeType.Element && name == Name) return true; return false; } public virtual bool ReadToFollowing (string localName, string namespaceURI) { while (Read ()) if (NodeType == XmlNodeType.Element && localName == LocalName && namespaceURI == NamespaceURI) return true; return false; } public virtual bool ReadToNextSibling (string name) { if (ReadState != ReadState.Interactive) return false; MoveToElement (); int depth = Depth; Skip (); for (; !EOF && depth <= Depth; Skip ()) if (NodeType == XmlNodeType.Element && name == Name) return true; return false; } public virtual bool ReadToNextSibling (string localName, string namespaceURI) { if (ReadState != ReadState.Interactive) return false; int depth = Depth; Skip (); for (; !EOF && depth <= Depth; Skip ()) if (NodeType == XmlNodeType.Element && localName == LocalName && namespaceURI == NamespaceURI) return true; return false; } public virtual XmlReader ReadSubtree () { if (NodeType != XmlNodeType.Element) throw new InvalidOperationException (String.Format ("ReadSubtree() can be invoked only when the reader is positioned on an element. Current node is {0}. {1}", NodeType, GetLocation ())); return new SubtreeXmlReader (this); } private string ReadContentString () { // The latter condition indicates that this XmlReader is on an attribute value // (HasAttributes is to indicate it is on attribute value). if (NodeType == XmlNodeType.Attribute || NodeType != XmlNodeType.Element && HasAttributes) return Value; return ReadContentString (true); } private string ReadContentString (bool isText) { if (isText) { switch (NodeType) { case XmlNodeType.Text: case XmlNodeType.SignificantWhitespace: case XmlNodeType.Whitespace: case XmlNodeType.CDATA: break; case XmlNodeType.Element: throw new InvalidOperationException (String.Format ("Node type {0} is not supported in this operation.{1}", NodeType, GetLocation ())); default: return String.Empty; } } string value = String.Empty; do { switch (NodeType) { case XmlNodeType.Element: if (isText) return value; throw XmlError ("Child element is not expected in this operation."); case XmlNodeType.EndElement: return value; case XmlNodeType.Text: case XmlNodeType.CDATA: case XmlNodeType.SignificantWhitespace: case XmlNodeType.Whitespace: value += Value; break; } } while (Read ()); throw XmlError ("Unexpected end of document."); } string GetLocation () { IXmlLineInfo li = this as IXmlLineInfo; return li != null && li.HasLineInfo () ? String.Format (" {0} (line {1}, column {2})", BaseURI, li.LineNumber, li.LinePosition) : String.Empty; } [MonoTODO] public virtual object ReadElementContentAsObject () { return ReadElementContentAs (ValueType, null); } [MonoTODO] public virtual object ReadElementContentAsObject (string localName, string namespaceURI) { return ReadElementContentAs (ValueType, null, localName, namespaceURI); } [MonoTODO] public virtual object ReadContentAsObject () { return ReadContentAs (ValueType, null); } public virtual object ReadElementContentAs (Type type, IXmlNamespaceResolver resolver) { bool isEmpty = IsEmptyElement; ReadStartElement (); object obj = ValueAs (isEmpty ? String.Empty : ReadContentString (false), type, resolver, false); if (!isEmpty) ReadEndElement (); return obj; } public virtual object ReadElementContentAs (Type type, IXmlNamespaceResolver resolver, string localName, string namespaceURI) { bool isEmpty = IsEmptyElement; ReadStartElement (localName, namespaceURI); if (isEmpty) return ValueAs (String.Empty, type, resolver, false); object obj = ReadContentAs (type, resolver); ReadEndElement (); return obj; } public virtual object ReadContentAs (Type type, IXmlNamespaceResolver resolver) { return ValueAs (ReadContentString (), type, resolver, false); } private object ValueAs (string text, Type type, IXmlNamespaceResolver resolver, bool isArrayItem) { try { if (type == typeof (object)) return text; if (type.IsArray && !isArrayItem) { var elemType = type.GetElementType (); var sarr = text.Split ((string []) null, StringSplitOptions.RemoveEmptyEntries); var ret = Array.CreateInstance (elemType, sarr.Length); for (int i = 0; i < ret.Length; i++) ret.SetValue (ValueAs (sarr [i], elemType, resolver, true), i); return ret; } if (type == typeof (XmlQualifiedName)) { if (resolver != null) return XmlQualifiedName.Parse (text, resolver, true); else return XmlQualifiedName.Parse (text, this, true); } if (type == typeof (Uri)) return XmlConvert.ToUri (text); if (type == typeof (TimeSpan)) return XmlConvert.ToTimeSpan (text); if (type == typeof (DateTimeOffset)) return XmlConvert.ToDateTimeOffset (text); switch (Type.GetTypeCode (type)) { case TypeCode.Boolean: return XQueryConvert.StringToBoolean (text); case TypeCode.DateTime: return XQueryConvert.StringToDateTime (text); case TypeCode.Decimal: return XQueryConvert.StringToDecimal (text); case TypeCode.Double: return XQueryConvert.StringToDouble (text); case TypeCode.Int32: return XQueryConvert.StringToInt (text); case TypeCode.Int64: return XQueryConvert.StringToInteger (text); case TypeCode.Single: return XQueryConvert.StringToFloat (text); case TypeCode.String: return text; } } catch (Exception ex) { throw XmlError (String.Format ("Current text value '{0}' is not acceptable for specified type '{1}'. {2}", text, type, ex != null ? ex.Message : String.Empty), ex); } throw new ArgumentException (String.Format ("Specified type '{0}' is not supported.", type)); } public virtual bool ReadElementContentAsBoolean () { try { return XQueryConvert.StringToBoolean (ReadElementContentAsString ()); } catch (FormatException ex) { throw XmlError ("Typed value is invalid.", ex); } } public virtual DateTime ReadElementContentAsDateTime () { try { return XQueryConvert.StringToDateTime (ReadElementContentAsString ()); } catch (FormatException ex) { throw XmlError ("Typed value is invalid.", ex); } } public virtual decimal ReadElementContentAsDecimal () { try { return XQueryConvert.StringToDecimal (ReadElementContentAsString ()); } catch (FormatException ex) { throw XmlError ("Typed value is invalid.", ex); } } public virtual double ReadElementContentAsDouble () { try { return XQueryConvert.StringToDouble (ReadElementContentAsString ()); } catch (FormatException ex) { throw XmlError ("Typed value is invalid.", ex); } } public virtual float ReadElementContentAsFloat () { try { return XQueryConvert.StringToFloat (ReadElementContentAsString ()); } catch (FormatException ex) { throw XmlError ("Typed value is invalid.", ex); } } public virtual int ReadElementContentAsInt () { try { return XQueryConvert.StringToInt (ReadElementContentAsString ()); } catch (FormatException ex) { throw XmlError ("Typed value is invalid.", ex); } } public virtual long ReadElementContentAsLong () { try { return XQueryConvert.StringToInteger (ReadElementContentAsString ()); } catch (FormatException ex) { throw XmlError ("Typed value is invalid.", ex); } } public virtual string ReadElementContentAsString () { bool isEmpty = IsEmptyElement; // unlike ReadStartElement() it rejects non-content nodes (this check is done before MoveToContent()) if (NodeType != XmlNodeType.Element) throw new InvalidOperationException (String.Format ("'{0}' is an element node.", NodeType)); ReadStartElement (); if (isEmpty) return String.Empty; string s = ReadContentString (false); ReadEndElement (); return s; } public virtual bool ReadElementContentAsBoolean (string localName, string namespaceURI) { try { return XQueryConvert.StringToBoolean (ReadElementContentAsString (localName, namespaceURI)); } catch (FormatException ex) { throw XmlError ("Typed value is invalid.", ex); } } public virtual DateTime ReadElementContentAsDateTime (string localName, string namespaceURI) { try { return XQueryConvert.StringToDateTime (ReadElementContentAsString (localName, namespaceURI)); } catch (FormatException ex) { throw XmlError ("Typed value is invalid.", ex); } } public virtual decimal ReadElementContentAsDecimal (string localName, string namespaceURI) { try { return XQueryConvert.StringToDecimal (ReadElementContentAsString (localName, namespaceURI)); } catch (FormatException ex) { throw XmlError ("Typed value is invalid.", ex); } } public virtual double ReadElementContentAsDouble (string localName, string namespaceURI) { try { return XQueryConvert.StringToDouble (ReadElementContentAsString (localName, namespaceURI)); } catch (FormatException ex) { throw XmlError ("Typed value is invalid.", ex); } } public virtual float ReadElementContentAsFloat (string localName, string namespaceURI) { try { return XQueryConvert.StringToFloat (ReadElementContentAsString (localName, namespaceURI)); } catch (FormatException ex) { throw XmlError ("Typed value is invalid.", ex); } } public virtual int ReadElementContentAsInt (string localName, string namespaceURI) { try { return XQueryConvert.StringToInt (ReadElementContentAsString (localName, namespaceURI)); } catch (FormatException ex) { throw XmlError ("Typed value is invalid.", ex); } } public virtual long ReadElementContentAsLong (string localName, string namespaceURI) { try { return XQueryConvert.StringToInteger (ReadElementContentAsString (localName, namespaceURI)); } catch (FormatException ex) { throw XmlError ("Typed value is invalid.", ex); } } public virtual string ReadElementContentAsString (string localName, string namespaceURI) { bool isEmpty = IsEmptyElement; // unlike ReadStartElement() it rejects non-content nodes (this check is done before MoveToContent()) if (NodeType != XmlNodeType.Element) throw new InvalidOperationException (String.Format ("'{0}' is an element node.", NodeType)); ReadStartElement (localName, namespaceURI); if (isEmpty) return String.Empty; string s = ReadContentString (false); ReadEndElement (); return s; } public virtual bool ReadContentAsBoolean () { try { return XQueryConvert.StringToBoolean (ReadContentString ()); } catch (FormatException ex) { throw XmlError ("Typed value is invalid.", ex); } } public virtual DateTime ReadContentAsDateTime () { try { return XQueryConvert.StringToDateTime (ReadContentString ()); } catch (FormatException ex) { throw XmlError ("Typed value is invalid.", ex); } } public virtual decimal ReadContentAsDecimal () { try { return XQueryConvert.StringToDecimal (ReadContentString ()); } catch (FormatException ex) { throw XmlError ("Typed value is invalid.", ex); } } public virtual double ReadContentAsDouble () { try { return XQueryConvert.StringToDouble (ReadContentString ()); } catch (FormatException ex) { throw XmlError ("Typed value is invalid.", ex); } } public virtual float ReadContentAsFloat () { try { return XQueryConvert.StringToFloat (ReadContentString ()); } catch (FormatException ex) { throw XmlError ("Typed value is invalid.", ex); } } public virtual int ReadContentAsInt () { try { return XQueryConvert.StringToInt (ReadContentString ()); } catch (FormatException ex) { throw XmlError ("Typed value is invalid.", ex); } } public virtual long ReadContentAsLong () { try { return XQueryConvert.StringToInteger (ReadContentString ()); } catch (FormatException ex) { throw XmlError ("Typed value is invalid.", ex); } } public virtual string ReadContentAsString () { return ReadContentString (); } public virtual int ReadContentAsBase64 ( byte [] buffer, int offset, int length) { CheckSupport (); return binary.ReadContentAsBase64 ( buffer, offset, length); } public virtual int ReadContentAsBinHex ( byte [] buffer, int offset, int length) { CheckSupport (); return binary.ReadContentAsBinHex ( buffer, offset, length); } public virtual int ReadElementContentAsBase64 ( byte [] buffer, int offset, int length) { CheckSupport (); return binary.ReadElementContentAsBase64 ( buffer, offset, length); } public virtual int ReadElementContentAsBinHex ( byte [] buffer, int offset, int length) { CheckSupport (); return binary.ReadElementContentAsBinHex ( buffer, offset, length); } private void CheckSupport () { // Default implementation expects both. if (!CanReadBinaryContent || !CanReadValueChunk) throw new NotSupportedException (); if (binary == null) binary = new XmlReaderBinarySupport (this); } #endif #if NET_2_0 public virtual int ReadValueChunk ( char [] buffer, int offset, int length) #else internal virtual int ReadValueChunk ( char [] buffer, int offset, int length) #endif { if (!CanReadValueChunk) throw new NotSupportedException (); if (binary == null) binary = new XmlReaderBinarySupport (this); return binary.ReadValueChunk (buffer, offset, length); } public abstract void ResolveEntity (); public virtual void Skip () { if (ReadState != ReadState.Interactive) return; MoveToElement (); if (NodeType != XmlNodeType.Element || IsEmptyElement) { Read (); return; } int depth = Depth; while (Read () && depth < Depth) ; if (NodeType == XmlNodeType.EndElement) Read (); } private XmlException XmlError (string message) { return new XmlException (this as IXmlLineInfo, BaseURI, message); } #if NET_2_0 private XmlException XmlError (string message, Exception innerException) { return new XmlException (this as IXmlLineInfo, BaseURI, message); } #endif #endregion } }