2014-08-13 10:39:27 +01:00
//
// 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 ;
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
using Mono.Xml ; // only required for NET_2_0
#if NET_4_5
using System.Threading ;
using System.Threading.Tasks ;
#endif
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 ; }
}
#if NET_4_0
public virtual bool HasValue {
get {
switch ( NodeType ) {
case XmlNodeType . Attribute :
case XmlNodeType . Comment :
case XmlNodeType . ProcessingInstruction :
case XmlNodeType . SignificantWhitespace :
case XmlNodeType . CDATA :
case XmlNodeType . Text :
case XmlNodeType . Whitespace :
case XmlNodeType . XmlDeclaration :
return true ;
}
return false ;
}
}
#else
public abstract bool HasValue { get ; }
#endif
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
public virtual IXmlSchemaInfo SchemaInfo {
get { return null ; }
}
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
#if NET_4_5
public virtual void Close ( )
{
if ( asyncRunning )
throw new InvalidOperationException ( "An asynchronous operation is already in progress." ) ;
}
#else
public abstract void Close ( ) ;
#endif
#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 input )
{
return Create ( input , null ) ;
}
public static XmlReader Create ( string inputUri )
{
return Create ( inputUri , null ) ;
}
public static XmlReader Create ( TextReader input )
{
return Create ( input , null ) ;
}
public static XmlReader Create ( string inputUri , XmlReaderSettings settings )
{
return Create ( inputUri , settings , null ) ;
}
public static XmlReader Create ( Stream input , XmlReaderSettings settings )
{
return Create ( input , settings , String . Empty ) ;
}
public static XmlReader Create ( TextReader input , XmlReaderSettings settings )
{
return Create ( input , settings , String . Empty ) ;
}
static XmlReaderSettings PopulateSettings ( XmlReaderSettings src )
{
XmlReaderSettings copy ;
if ( src = = null )
copy = new XmlReaderSettings ( ) ;
else
copy = src . Clone ( ) ;
#if NET_4_5
copy . SetReadOnly ( ) ;
#endif
return copy ;
}
static XmlReaderSettings PopulateSettings ( XmlReader reader , XmlReaderSettings src )
{
XmlReaderSettings copy ;
if ( src = = null )
copy = new XmlReaderSettings ( ) ;
else
copy = src . Clone ( ) ;
#if NET_4_5
if ( reader . Settings ! = null )
copy . Async = reader . Settings . Async ;
copy . SetReadOnly ( ) ;
#endif
return copy ;
}
public static XmlReader Create ( Stream input , XmlReaderSettings settings , string baseUri )
{
settings = PopulateSettings ( settings ) ;
return Create ( input , settings ,
PopulateParserContext ( settings , baseUri ) ) ;
}
public static XmlReader Create ( TextReader input , XmlReaderSettings settings , string baseUri )
{
settings = PopulateSettings ( settings ) ;
return Create ( input , settings ,
PopulateParserContext ( settings , baseUri ) ) ;
}
public static XmlReader Create ( XmlReader reader , XmlReaderSettings settings )
{
settings = PopulateSettings ( reader , settings ) ;
XmlReader r = CreateFilteredXmlReader ( reader , settings ) ;
r . settings = settings ;
return r ;
}
public static XmlReader Create ( string inputUri , XmlReaderSettings settings , XmlParserContext inputContext )
{
settings = PopulateSettings ( settings ) ;
bool closeInputBak = settings . CloseInput ;
try {
settings . CloseInput = true ; // forced. See XmlReaderCommonTests.CreateFromUrlClose().
if ( inputContext = = null )
inputContext = PopulateParserContext ( settings , inputUri ) ;
XmlTextReader xtr = new XmlTextReader ( false , settings . XmlResolver , inputUri , GetNodeType ( settings ) , inputContext ) ;
XmlReader ret = CreateCustomizedTextReader ( xtr , settings ) ;
return ret ;
} finally {
settings . CloseInput = closeInputBak ;
}
}
public static XmlReader Create ( Stream input , XmlReaderSettings settings , XmlParserContext inputContext )
{
settings = PopulateSettings ( settings ) ;
if ( inputContext = = null )
inputContext = PopulateParserContext ( settings , String . Empty ) ;
return CreateCustomizedTextReader ( new XmlTextReader ( input , GetNodeType ( settings ) , inputContext ) , settings ) ;
}
public static XmlReader Create ( TextReader input , XmlReaderSettings settings , XmlParserContext inputContext )
{
settings = PopulateSettings ( settings ) ;
if ( inputContext = = null )
inputContext = PopulateParserContext ( settings , String . Empty ) ;
return CreateCustomizedTextReader ( new XmlTextReader ( inputContext . BaseURI , input , GetNodeType ( settings ) , inputContext ) , 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 )
{
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 ;
}
#if NET_4_0
public void Dispose ( )
#else
void IDisposable . Dispose ( )
#endif
{
2014-10-04 11:27:48 +01:00
Dispose ( true ) ;
2014-08-13 10:39:27 +01:00
}
protected virtual void Dispose ( bool disposing )
{
2014-10-04 11:27:48 +01:00
if ( disposing & & ReadState ! = ReadState . Closed )
2014-08-13 10:39:27 +01:00
Close ( ) ;
}
#endif
public abstract string GetAttribute ( int i ) ;
public abstract string GetAttribute ( string name ) ;
public abstract string GetAttribute ( string name , string namespaceURI ) ;
public static bool IsName ( string str )
{
return str ! = null & & XmlChar . IsName ( str ) ;
}
public static bool IsNameToken ( string str )
{
return str ! = null & & XmlChar . IsNmToken ( str ) ;
}
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 ns )
{
if ( ! IsStartElement ( ) )
return false ;
return ( LocalName = = localname & & NamespaceURI = = ns ) ;
}
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 name , string ns ) ;
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 ns )
{
if ( MoveToContent ( ) ! = XmlNodeType . Element ) {
string error = String . Format ( "'{0}' is an invalid node type." ,
NodeType . ToString ( ) ) ;
throw XmlError ( error ) ;
}
if ( localname ! = LocalName | | NamespaceURI ! = ns ) {
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 ns )
{
if ( MoveToContent ( ) ! = XmlNodeType . Element ) {
string error = String . Format ( "'{0}' is an invalid node type." ,
NodeType . ToString ( ) ) ;
throw XmlError ( error ) ;
}
if ( localname ! = LocalName | | NamespaceURI ! = ns ) {
string error = String . Format ( "Expecting {0} tag from namespace {1}, got {2} and {3} instead" ,
localname , ns ,
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 ) ;
}
#if NET_4_5
public virtual DateTimeOffset ReadContentAsDateTimeOffset ( )
{
try {
return XmlConvert . ToDateTimeOffset ( ReadContentString ( ) ) ;
} catch ( Exception e ) {
throw XmlError ( "Typed value is invalid." , e ) ;
}
}
#endif
public virtual object ReadElementContentAs ( Type returnType , IXmlNamespaceResolver namespaceResolver )
{
bool isEmpty = IsEmptyElement ;
ReadStartElement ( ) ;
object obj = ValueAs ( isEmpty ? String . Empty : ReadContentString ( false ) , returnType , namespaceResolver , false ) ;
if ( ! isEmpty )
ReadEndElement ( ) ;
return obj ;
}
public virtual object ReadElementContentAs ( Type returnType , IXmlNamespaceResolver namespaceResolver , string localName , string namespaceURI )
{
if ( localName = = null )
throw new ArgumentNullException ( "localName" ) ;
if ( namespaceURI = = null )
throw new ArgumentNullException ( "namespaceURI" ) ;
bool isEmpty = IsEmptyElement ;
ReadStartElement ( localName , namespaceURI ) ;
if ( isEmpty )
return ValueAs ( String . Empty , returnType , namespaceResolver , false ) ;
object obj = ReadContentAs ( returnType , namespaceResolver ) ;
ReadEndElement ( ) ;
return obj ;
}
public virtual object ReadContentAs ( Type returnType , IXmlNamespaceResolver namespaceResolver )
{
return ValueAs ( ReadContentString ( ) , returnType , namespaceResolver , 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 . Byte :
return XmlConvert . ToByte ( text ) ;
case TypeCode . SByte :
return XmlConvert . ToSByte ( text ) ;
case TypeCode . Int16 :
return XmlConvert . ToInt16 ( text ) ;
case TypeCode . UInt16 :
return XQueryConvert . StringToUnsignedShort ( text ) ;
case TypeCode . Int32 :
return XQueryConvert . StringToInt ( text ) ;
case TypeCode . UInt32 :
return XQueryConvert . StringToUnsignedInt ( text ) ;
case TypeCode . Int64 :
return XQueryConvert . StringToInteger ( text ) ;
case TypeCode . UInt64 :
return XQueryConvert . StringToUnsignedLong ( text ) ;
case TypeCode . DateTime :
return XQueryConvert . StringToDateTime ( text ) ;
case TypeCode . Decimal :
return XQueryConvert . StringToDecimal ( text ) ;
case TypeCode . Double :
return XQueryConvert . StringToDouble ( 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 XmlException ( 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 index , int count )
{
CheckSupport ( ) ;
return binary . ReadContentAsBase64 (
buffer , index , count ) ;
}
public virtual int ReadContentAsBinHex (
byte [ ] buffer , int index , int count )
{
CheckSupport ( ) ;
return binary . ReadContentAsBinHex (
buffer , index , count ) ;
}
public virtual int ReadElementContentAsBase64 (
byte [ ] buffer , int index , int count )
{
CheckSupport ( ) ;
return binary . ReadElementContentAsBase64 (
buffer , index , count ) ;
}
public virtual int ReadElementContentAsBinHex (
byte [ ] buffer , int index , int count )
{
CheckSupport ( ) ;
return binary . ReadElementContentAsBinHex (
buffer , index , count ) ;
}
private void CheckSupport ( )
{
// Default implementation expects both.
if ( ! CanReadBinaryContent | | ! CanReadValueChunk )
throw new NotSupportedException ( ) ;
if ( binary = = null )
binary = new XmlReaderBinarySupport ( this ) ;
}
#endif
public virtual int ReadValueChunk ( char [ ] buffer , int index , int count )
{
if ( ! CanReadValueChunk )
throw new NotSupportedException ( ) ;
if ( binary = = null )
binary = new XmlReaderBinarySupport ( this ) ;
return binary . ReadValueChunk ( buffer , index , count ) ;
}
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
#if NET_4_5
#region . NET 4.5 Async Methods
bool asyncRunning ;
void StartAsync ( )
{
if ( ! settings . Async )
throw new InvalidOperationException ( "Set XmlReaderSettings.Async to true if you want to use Async Methods." ) ;
lock ( this ) {
if ( asyncRunning )
throw new InvalidOperationException ( "An asynchronous operation is already in progress." ) ;
asyncRunning = true ;
}
}
public virtual Task < bool > ReadAsync ( )
{
StartAsync ( ) ;
return Task . Run ( ( ) = > {
try {
return Read ( ) ;
} finally {
asyncRunning = false ;
}
} ) ;
}
public virtual Task < string > GetValueAsync ( )
{
StartAsync ( ) ;
return Task . Run ( ( ) = > {
try {
return Value ;
} finally {
asyncRunning = false ;
}
} ) ;
}
public virtual Task < string > ReadInnerXmlAsync ( )
{
StartAsync ( ) ;
return Task . Run ( ( ) = > {
try {
return ReadInnerXml ( ) ;
} finally {
asyncRunning = false ;
}
} ) ;
}
public virtual Task < string > ReadOuterXmlAsync ( )
{
StartAsync ( ) ;
return Task . Run ( ( ) = > {
try {
return ReadOuterXml ( ) ;
} finally {
asyncRunning = false ;
}
} ) ;
}
public virtual Task < string > ReadContentAsStringAsync ( )
{
StartAsync ( ) ;
return Task . Run ( ( ) = > {
try {
return ReadContentAsString ( ) ;
} finally {
asyncRunning = false ;
}
} ) ;
}
public virtual Task < int > ReadContentAsBase64Async ( byte [ ] buffer , int index , int count )
{
StartAsync ( ) ;
return Task . Run ( ( ) = > {
try {
return ReadContentAsBase64 ( buffer , index , count ) ;
} finally {
asyncRunning = false ;
}
} ) ;
}
public virtual Task < int > ReadContentAsBinHexAsync ( byte [ ] buffer , int index , int count )
{
StartAsync ( ) ;
return Task . Run ( ( ) = > {
try {
return ReadContentAsBinHex ( buffer , index , count ) ;
} finally {
asyncRunning = false ;
}
} ) ;
}
public virtual Task < int > ReadElementContentAsBase64Async ( byte [ ] buffer , int index , int count )
{
StartAsync ( ) ;
return Task . Run ( ( ) = > {
try {
return ReadElementContentAsBase64 ( buffer , index , count ) ;
} finally {
asyncRunning = false ;
}
} ) ;
}
public virtual Task < int > ReadElementContentAsBinHexAsync ( byte [ ] buffer , int index , int count )
{
StartAsync ( ) ;
return Task . Run ( ( ) = > {
try {
return ReadElementContentAsBinHex ( buffer , index , count ) ;
} finally {
asyncRunning = false ;
}
} ) ;
}
public virtual Task < int > ReadValueChunkAsync ( char [ ] buffer , int index , int count )
{
StartAsync ( ) ;
return Task . Run ( ( ) = > {
try {
return ReadValueChunk ( buffer , index , count ) ;
} finally {
asyncRunning = false ;
}
} ) ;
}
public virtual Task < object > ReadContentAsAsync ( Type returnType , IXmlNamespaceResolver namespaceResolver )
{
StartAsync ( ) ;
return Task . Run ( ( ) = > {
try {
return ReadContentAs ( returnType , namespaceResolver ) ;
} finally {
asyncRunning = false ;
}
} ) ;
}
public virtual Task < object > ReadContentAsObjectAsync ( )
{
StartAsync ( ) ;
return Task . Run ( ( ) = > {
try {
return ReadContentAsObject ( ) ;
} finally {
asyncRunning = false ;
}
} ) ;
}
public virtual Task < object > ReadElementContentAsAsync ( Type returnType , IXmlNamespaceResolver namespaceResolver )
{
StartAsync ( ) ;
return Task . Run ( ( ) = > {
try {
return ReadElementContentAs ( returnType , namespaceResolver ) ;
} finally {
asyncRunning = false ;
}
} ) ;
}
public virtual Task < object > ReadElementContentAsObjectAsync ( )
{
StartAsync ( ) ;
return Task . Run ( ( ) = > {
try {
return ReadElementContentAsObject ( ) ;
} finally {
asyncRunning = false ;
}
} ) ;
}
public virtual Task < string > ReadElementContentAsStringAsync ( )
{
StartAsync ( ) ;
return Task . Run ( ( ) = > {
try {
return ReadElementContentAsString ( ) ;
} finally {
asyncRunning = false ;
}
} ) ;
}
public virtual Task < XmlNodeType > MoveToContentAsync ( )
{
StartAsync ( ) ;
return Task . Run ( ( ) = > {
try {
return MoveToContent ( ) ;
} finally {
asyncRunning = false ;
}
} ) ;
}
public virtual Task SkipAsync ( )
{
StartAsync ( ) ;
return Task . Run ( ( ) = > {
try {
Skip ( ) ;
} finally {
asyncRunning = false ;
}
} ) ;
}
#endregion
#endif
}
}