5 // Jason Diamond (jason@injektilo.org)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
9 // (C) 2001, 2002 Jason Diamond http://injektilo.org/
10 // (c) 2002 Ximian, Inc. (http://www.ximian.com)
11 // (C) 2003 Atsushi Enomoto
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System.Collections;
35 using System.Diagnostics;
38 using System.Xml.Schema; // only required for NET_2_0 (SchemaInfo)
39 using System.Xml.Serialization; // only required for NET_2_0 (SchemaInfo)
40 using Mono.Xml.Schema; // only required for NET_2_0
41 using Mono.Xml; // only required for NET_2_0
43 using System.Threading;
44 using System.Threading.Tasks;
50 public abstract class XmlReader : IDisposable
52 public abstract class XmlReader
55 private StringBuilder readStringBuffer;
56 private XmlReaderBinarySupport binary;
58 private XmlReaderSettings settings;
63 protected XmlReader ()
71 public abstract int AttributeCount { get; }
73 public abstract string BaseURI { get; }
75 internal XmlReaderBinarySupport Binary {
76 get { return binary; }
79 internal XmlReaderBinarySupport.CharGetter BinaryCharGetter {
80 get { return binary != null ? binary.Getter : null; }
83 binary = new XmlReaderBinarySupport (this);
84 binary.Getter = value;
89 // To enable it internally in sys.xml, just insert these
90 // two lines into Read():
93 // if (Binary != null)
97 public virtual bool CanReadBinaryContent {
101 public virtual bool CanReadValueChunk {
102 get { return false; }
105 internal virtual bool CanReadBinaryContent {
106 get { return false; }
109 internal virtual bool CanReadValueChunk {
110 get { return false; }
114 public virtual bool CanResolveEntity
116 get { return false; }
119 public abstract int Depth { get; }
121 public abstract bool EOF { get; }
123 public virtual bool HasAttributes
125 get { return AttributeCount > 0; }
129 public virtual bool HasValue {
132 case XmlNodeType.Attribute:
133 case XmlNodeType.Comment:
134 case XmlNodeType.ProcessingInstruction:
135 case XmlNodeType.SignificantWhitespace:
136 case XmlNodeType.CDATA:
137 case XmlNodeType.Text:
138 case XmlNodeType.Whitespace:
139 case XmlNodeType.XmlDeclaration:
146 public abstract bool HasValue { get; }
149 public abstract bool IsEmptyElement { get; }
152 public virtual bool IsDefault {
153 get { return false; }
156 public virtual string this [int i] {
157 get { return GetAttribute (i); }
160 public virtual string this [string name] {
161 get { return GetAttribute (name); }
164 public virtual string this [string name, string namespaceURI] {
165 get { return GetAttribute (name, namespaceURI); }
168 public abstract bool IsDefault { get; }
170 public abstract string this [int i] { get; }
172 public abstract string this [string name] { get; }
174 public abstract string this [string localName, string namespaceName] { get; }
177 public abstract string LocalName { get; }
180 public virtual string Name {
182 return Prefix.Length > 0 ?
183 String.Concat (Prefix, ":", LocalName) :
188 public abstract string Name { get; }
191 public abstract string NamespaceURI { get; }
193 public abstract XmlNameTable NameTable { get; }
195 public abstract XmlNodeType NodeType { get; }
197 public abstract string Prefix { get; }
200 public virtual char QuoteChar {
204 public abstract char QuoteChar { get; }
207 public abstract ReadState ReadState { get; }
210 public virtual IXmlSchemaInfo SchemaInfo {
214 public virtual XmlReaderSettings Settings {
215 get { return settings; }
219 public abstract string Value { get; }
222 public virtual string XmlLang {
223 get { return String.Empty; }
226 public virtual XmlSpace XmlSpace {
227 get { return XmlSpace.None; }
230 public abstract string XmlLang { get; }
232 public abstract XmlSpace XmlSpace { get; }
240 public virtual void Close ()
243 throw new InvalidOperationException ("An asynchronous operation is already in progress.");
246 public abstract void Close ();
250 private static XmlNameTable PopulateNameTable (
251 XmlReaderSettings settings)
253 XmlNameTable nameTable = settings.NameTable;
254 if (nameTable == null)
255 nameTable = new NameTable ();
259 private static XmlParserContext PopulateParserContext (
260 XmlReaderSettings settings, string baseUri)
262 XmlNameTable nt = PopulateNameTable (settings);
263 return new XmlParserContext (nt,
264 new XmlNamespaceManager (nt),
275 private static XmlNodeType GetNodeType (
276 XmlReaderSettings settings)
278 ConformanceLevel level = settings != null ? settings.ConformanceLevel : ConformanceLevel.Auto;
280 level == ConformanceLevel.Fragment ?
281 XmlNodeType.Element :
282 XmlNodeType.Document;
285 public static XmlReader Create (Stream input)
287 return Create (input, null);
290 public static XmlReader Create (string inputUri)
292 return Create (inputUri, null);
295 public static XmlReader Create (TextReader input)
297 return Create (input, null);
300 public static XmlReader Create (string inputUri, XmlReaderSettings settings)
302 return Create (inputUri, settings, null);
305 public static XmlReader Create (Stream input, XmlReaderSettings settings)
307 return Create (input, settings, String.Empty);
310 public static XmlReader Create (TextReader input, XmlReaderSettings settings)
312 return Create (input, settings, String.Empty);
315 static XmlReaderSettings PopulateSettings (XmlReaderSettings src)
317 XmlReaderSettings copy;
319 copy = new XmlReaderSettings ();
328 static XmlReaderSettings PopulateSettings (XmlReader reader, XmlReaderSettings src)
330 XmlReaderSettings copy;
332 copy = new XmlReaderSettings ();
336 if (reader.Settings != null)
337 copy.Async = reader.Settings.Async;
343 public static XmlReader Create (Stream input, XmlReaderSettings settings, string baseUri)
345 settings = PopulateSettings (settings);
346 return Create (input, settings,
347 PopulateParserContext (settings, baseUri));
350 public static XmlReader Create (TextReader input, XmlReaderSettings settings, string baseUri)
352 settings = PopulateSettings (settings);
353 return Create (input, settings,
354 PopulateParserContext (settings, baseUri));
357 public static XmlReader Create (XmlReader reader, XmlReaderSettings settings)
359 settings = PopulateSettings (reader, settings);
360 XmlReader r = CreateFilteredXmlReader (reader, settings);
361 r.settings = settings;
365 public static XmlReader Create (string inputUri, XmlReaderSettings settings, XmlParserContext inputContext)
367 settings = PopulateSettings (settings);
368 bool closeInputBak = settings.CloseInput;
370 settings.CloseInput = true; // forced. See XmlReaderCommonTests.CreateFromUrlClose().
371 if (inputContext == null)
372 inputContext = PopulateParserContext (settings, inputUri);
373 XmlTextReader xtr = new XmlTextReader (false, settings.XmlResolver, inputUri, GetNodeType (settings), inputContext);
374 XmlReader ret = CreateCustomizedTextReader (xtr, settings);
377 settings.CloseInput = closeInputBak;
381 public static XmlReader Create (Stream input, XmlReaderSettings settings, XmlParserContext inputContext)
383 settings = PopulateSettings (settings);
384 if (inputContext == null)
385 inputContext = PopulateParserContext (settings, String.Empty);
386 return CreateCustomizedTextReader (new XmlTextReader (input, GetNodeType (settings), inputContext), settings);
389 public static XmlReader Create (TextReader input, XmlReaderSettings settings, XmlParserContext inputContext)
391 settings = PopulateSettings (settings);
392 if (inputContext == null)
393 inputContext = PopulateParserContext (settings, String.Empty);
394 return CreateCustomizedTextReader (new XmlTextReader (inputContext.BaseURI, input, GetNodeType (settings), inputContext), settings);
397 private static XmlReader CreateCustomizedTextReader (XmlTextReader reader, XmlReaderSettings settings)
399 reader.XmlResolver = settings.XmlResolver;
400 // Normalization is set true by default.
401 reader.Normalization = true;
402 reader.EntityHandling = EntityHandling.ExpandEntities;
404 if (settings.ProhibitDtd)
405 reader.ProhibitDtd = true;
407 if (!settings.CheckCharacters)
408 reader.CharacterChecking = false;
410 // I guess it might be changed in 2.0 RTM to set true
411 // as default, or just disappear. It goes against
412 // XmlTextReader's default usage and users will have
413 // to close input manually (that's annoying). Moreover,
414 // MS XmlTextReader consumes text input more than
415 // actually read and users can acquire those extra
416 // consumption by GetRemainder() that returns different
418 reader.CloseInput = settings.CloseInput;
420 // I would like to support it in detail later;
421 // MSDN description looks source of confusion. We don't
422 // need examples, but precise list of how it works.
423 reader.Conformance = settings.ConformanceLevel;
425 reader.AdjustLineInfoOffset (settings.LineNumberOffset,
426 settings.LinePositionOffset);
428 if (settings.NameTable != null)
429 reader.SetNameTable (settings.NameTable);
431 XmlReader r = CreateFilteredXmlReader (reader, settings);
432 r.settings = settings;
436 private static XmlReader CreateFilteredXmlReader (XmlReader reader, XmlReaderSettings settings)
438 ConformanceLevel conf = ConformanceLevel.Auto;
439 if (reader is XmlTextReader)
440 conf = ((XmlTextReader) reader).Conformance;
441 else if (reader.Settings != null)
442 conf = reader.Settings.ConformanceLevel;
444 conf = settings.ConformanceLevel;
445 if (settings.ConformanceLevel != ConformanceLevel.Auto &&
446 conf != settings.ConformanceLevel)
447 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));
448 settings.ConformanceLevel = conf;
450 reader = CreateValidatingXmlReader (reader, settings);
452 if ( settings.IgnoreComments ||
453 settings.IgnoreProcessingInstructions ||
454 settings.IgnoreWhitespace)
455 return new XmlFilterReader (reader, settings);
457 reader.settings = settings;
462 private static XmlReader CreateValidatingXmlReader (XmlReader reader, XmlReaderSettings settings)
464 XmlValidatingReader xvr = null;
465 switch (settings.ValidationType) {
466 // Auto and XDR are obsoleted in 2.0 and therefore ignored.
469 case ValidationType.DTD:
470 xvr = new XmlValidatingReader (reader);
471 xvr.XmlResolver = settings.XmlResolver;
472 xvr.ValidationType = ValidationType.DTD;
474 case ValidationType.Schema:
475 return new XmlSchemaValidatingReader (reader, settings);
478 // Actually I don't think they are treated in DTD validation though...
479 if ((settings.ValidationFlags & XmlSchemaValidationFlags.ProcessIdentityConstraints) == 0)
480 throw new NotImplementedException ();
481 //if ((settings.ValidationFlags & XmlSchemaValidationFlags.ProcessInlineSchema) != 0)
482 // throw new NotImplementedException ();
483 //if ((settings.ValidationFlags & XmlSchemaValidationFlags.ProcessSchemaLocation) != 0)
484 // throw new NotImplementedException ();
485 //if ((settings.ValidationFlags & XmlSchemaValidationFlags.ReportValidationWarnings) == 0)
486 // throw new NotImplementedException ();
488 return xvr != null ? xvr : reader;
492 public void Dispose ()
494 void IDisposable.Dispose()
500 protected virtual void Dispose (bool disposing)
502 if (ReadState != ReadState.Closed)
507 public abstract string GetAttribute (int i);
509 public abstract string GetAttribute (string name);
511 public abstract string GetAttribute (string name, string namespaceURI);
513 public static bool IsName (string str)
515 return str != null && XmlChar.IsName (str);
518 public static bool IsNameToken (string str)
520 return str != null && XmlChar.IsNmToken (str);
523 public virtual bool IsStartElement ()
525 return (MoveToContent () == XmlNodeType.Element);
528 public virtual bool IsStartElement (string name)
530 if (!IsStartElement ())
533 return (Name == name);
536 public virtual bool IsStartElement (string localname, string ns)
538 if (!IsStartElement ())
541 return (LocalName == localname && NamespaceURI == ns);
544 public abstract string LookupNamespace (string prefix);
547 public virtual void MoveToAttribute (int i)
549 if (i >= AttributeCount)
550 throw new ArgumentOutOfRangeException ();
551 MoveToFirstAttribute ();
552 for (int a = 0; a < i; a++)
553 MoveToNextAttribute ();
556 public abstract void MoveToAttribute (int i);
559 public abstract bool MoveToAttribute (string name);
561 public abstract bool MoveToAttribute (string name, string ns);
563 private bool IsContent (XmlNodeType nodeType)
566 * (non-white space text, CDATA, Element, EndElement, EntityReference, or EndEntity)
569 case XmlNodeType.Text:
571 case XmlNodeType.CDATA:
573 case XmlNodeType.Element:
575 case XmlNodeType.EndElement:
577 case XmlNodeType.EntityReference:
579 case XmlNodeType.EndEntity:
586 public virtual XmlNodeType MoveToContent ()
589 case ReadState.Initial:
590 case ReadState.Interactive:
596 if (NodeType == XmlNodeType.Attribute)
600 if (IsContent (NodeType))
604 return XmlNodeType.None;
607 public abstract bool MoveToElement ();
609 public abstract bool MoveToFirstAttribute ();
611 public abstract bool MoveToNextAttribute ();
613 public abstract bool Read ();
615 public abstract bool ReadAttributeValue ();
617 public virtual string ReadElementString ()
619 if (MoveToContent () != XmlNodeType.Element) {
620 string error = String.Format ("'{0}' is an invalid node type.",
621 NodeType.ToString ());
622 throw XmlError (error);
625 string result = String.Empty;
626 if (!IsEmptyElement) {
628 result = ReadString ();
629 if (NodeType != XmlNodeType.EndElement) {
630 string error = String.Format ("'{0}' is an invalid node type.",
631 NodeType.ToString ());
632 throw XmlError (error);
640 public virtual string ReadElementString (string name)
642 if (MoveToContent () != XmlNodeType.Element) {
643 string error = String.Format ("'{0}' is an invalid node type.",
644 NodeType.ToString ());
645 throw XmlError (error);
649 string error = String.Format ("The {0} tag from namespace {1} is expected.",
651 throw XmlError (error);
654 string result = String.Empty;
655 if (!IsEmptyElement) {
657 result = ReadString ();
658 if (NodeType != XmlNodeType.EndElement) {
659 string error = String.Format ("'{0}' is an invalid node type.",
660 NodeType.ToString ());
661 throw XmlError (error);
669 public virtual string ReadElementString (string localname, string ns)
671 if (MoveToContent () != XmlNodeType.Element) {
672 string error = String.Format ("'{0}' is an invalid node type.",
673 NodeType.ToString ());
674 throw XmlError (error);
677 if (localname != LocalName || NamespaceURI != ns) {
678 string error = String.Format ("The {0} tag from namespace {1} is expected.",
679 LocalName, NamespaceURI);
680 throw XmlError (error);
683 string result = String.Empty;
684 if (!IsEmptyElement) {
686 result = ReadString ();
687 if (NodeType != XmlNodeType.EndElement) {
688 string error = String.Format ("'{0}' is an invalid node type.",
689 NodeType.ToString ());
690 throw XmlError (error);
698 public virtual void ReadEndElement ()
700 if (MoveToContent () != XmlNodeType.EndElement) {
701 string error = String.Format ("'{0}' is an invalid node type.",
702 NodeType.ToString ());
703 throw XmlError (error);
709 public virtual string ReadInnerXml ()
711 if (ReadState != ReadState.Interactive || NodeType == XmlNodeType.EndElement)
714 if (IsEmptyElement) {
718 StringWriter sw = new StringWriter ();
719 XmlTextWriter xtw = new XmlTextWriter (sw);
720 if (NodeType == XmlNodeType.Element) {
721 int startDepth = Depth;
723 while (startDepth < Depth) {
724 if (ReadState != ReadState.Interactive)
725 throw XmlError ("Unexpected end of the XML reader.");
726 xtw.WriteNode (this, false);
728 // reader is now end element, then proceed once more.
732 xtw.WriteNode (this, false);
734 return sw.ToString ();
737 public virtual string ReadOuterXml ()
739 if (ReadState != ReadState.Interactive || NodeType == XmlNodeType.EndElement)
743 case XmlNodeType.Element:
744 case XmlNodeType.Attribute:
745 StringWriter sw = new StringWriter ();
746 XmlTextWriter xtw = new XmlTextWriter (sw);
747 xtw.WriteNode (this, false);
748 return sw.ToString ();
755 public virtual void ReadStartElement ()
757 if (MoveToContent () != XmlNodeType.Element) {
758 string error = String.Format ("'{0}' is an invalid node type.",
759 NodeType.ToString ());
760 throw XmlError (error);
766 public virtual void ReadStartElement (string name)
768 if (MoveToContent () != XmlNodeType.Element) {
769 string error = String.Format ("'{0}' is an invalid node type.",
770 NodeType.ToString ());
771 throw XmlError (error);
775 string error = String.Format ("The {0} tag from namespace {1} is expected.",
777 throw XmlError (error);
783 public virtual void ReadStartElement (string localname, string ns)
785 if (MoveToContent () != XmlNodeType.Element) {
786 string error = String.Format ("'{0}' is an invalid node type.",
787 NodeType.ToString ());
788 throw XmlError (error);
791 if (localname != LocalName || NamespaceURI != ns) {
792 string error = String.Format ("Expecting {0} tag from namespace {1}, got {2} and {3} instead",
794 LocalName, NamespaceURI);
795 throw XmlError (error);
801 public virtual string ReadString ()
803 if (readStringBuffer == null)
804 readStringBuffer = new StringBuilder ();
805 readStringBuffer.Length = 0;
812 case XmlNodeType.Element:
818 case XmlNodeType.Text:
819 case XmlNodeType.CDATA:
820 case XmlNodeType.Whitespace:
821 case XmlNodeType.SignificantWhitespace:
822 readStringBuffer.Append (Value);
828 case XmlNodeType.Text:
829 case XmlNodeType.CDATA:
830 case XmlNodeType.Whitespace:
831 case XmlNodeType.SignificantWhitespace:
834 case XmlNodeType.Text:
835 case XmlNodeType.CDATA:
836 case XmlNodeType.Whitespace:
837 case XmlNodeType.SignificantWhitespace:
838 readStringBuffer.Append (Value);
846 string ret = readStringBuffer.ToString ();
847 readStringBuffer.Length = 0;
852 public virtual Type ValueType {
853 get { return typeof (string); }
856 public virtual bool ReadToDescendant (string name)
858 if (ReadState == ReadState.Initial) {
860 if (IsStartElement (name))
863 if (NodeType != XmlNodeType.Element || IsEmptyElement)
866 for (Read (); depth < Depth; Read ())
867 if (NodeType == XmlNodeType.Element && name == Name)
872 public virtual bool ReadToDescendant (string localName, string namespaceURI)
874 if (ReadState == ReadState.Initial) {
876 if (IsStartElement (localName, namespaceURI))
879 if (NodeType != XmlNodeType.Element || IsEmptyElement)
882 for (Read (); depth < Depth; Read ())
883 if (NodeType == XmlNodeType.Element && localName == LocalName && namespaceURI == NamespaceURI)
888 public virtual bool ReadToFollowing (string name)
891 if (NodeType == XmlNodeType.Element && name == Name)
896 public virtual bool ReadToFollowing (string localName, string namespaceURI)
899 if (NodeType == XmlNodeType.Element && localName == LocalName && namespaceURI == NamespaceURI)
904 public virtual bool ReadToNextSibling (string name)
906 if (ReadState != ReadState.Interactive)
911 for (; !EOF && depth <= Depth; Skip ())
912 if (NodeType == XmlNodeType.Element && name == Name)
917 public virtual bool ReadToNextSibling (string localName, string namespaceURI)
919 if (ReadState != ReadState.Interactive)
923 for (; !EOF && depth <= Depth; Skip ())
924 if (NodeType == XmlNodeType.Element && localName == LocalName && namespaceURI == NamespaceURI)
929 public virtual XmlReader ReadSubtree ()
931 if (NodeType != XmlNodeType.Element)
932 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 ()));
933 return new SubtreeXmlReader (this);
936 private string ReadContentString ()
938 // The latter condition indicates that this XmlReader is on an attribute value
939 // (HasAttributes is to indicate it is on attribute value).
940 if (NodeType == XmlNodeType.Attribute || NodeType != XmlNodeType.Element && HasAttributes)
942 return ReadContentString (true);
945 private string ReadContentString (bool isText)
949 case XmlNodeType.Text:
950 case XmlNodeType.SignificantWhitespace:
951 case XmlNodeType.Whitespace:
952 case XmlNodeType.CDATA:
954 case XmlNodeType.Element:
955 throw new InvalidOperationException (String.Format ("Node type {0} is not supported in this operation.{1}", NodeType, GetLocation ()));
961 string value = String.Empty;
964 case XmlNodeType.Element:
967 throw XmlError ("Child element is not expected in this operation.");
968 case XmlNodeType.EndElement:
970 case XmlNodeType.Text:
971 case XmlNodeType.CDATA:
972 case XmlNodeType.SignificantWhitespace:
973 case XmlNodeType.Whitespace:
978 throw XmlError ("Unexpected end of document.");
981 string GetLocation ()
983 IXmlLineInfo li = this as IXmlLineInfo;
984 return li != null && li.HasLineInfo () ?
985 String.Format (" {0} (line {1}, column {2})", BaseURI, li.LineNumber, li.LinePosition) : String.Empty;
989 public virtual object ReadElementContentAsObject ()
991 return ReadElementContentAs (ValueType, null);
995 public virtual object ReadElementContentAsObject (string localName, string namespaceURI)
997 return ReadElementContentAs (ValueType, null, localName, namespaceURI);
1001 public virtual object ReadContentAsObject ()
1003 return ReadContentAs (ValueType, null);
1007 public virtual DateTimeOffset ReadContentAsDateTimeOffset ()
1010 return XmlConvert.ToDateTimeOffset (ReadContentString ());
1011 } catch (Exception e) {
1012 throw XmlError ("Typed value is invalid.", e);
1017 public virtual object ReadElementContentAs (Type returnType, IXmlNamespaceResolver namespaceResolver)
1019 bool isEmpty = IsEmptyElement;
1020 ReadStartElement ();
1021 object obj = ValueAs (isEmpty ? String.Empty : ReadContentString (false), returnType, namespaceResolver, false);
1027 public virtual object ReadElementContentAs (Type returnType, IXmlNamespaceResolver namespaceResolver, string localName, string namespaceURI)
1029 if (localName == null)
1030 throw new ArgumentNullException ("localName");
1031 if (namespaceURI == null)
1032 throw new ArgumentNullException ("namespaceURI");
1034 bool isEmpty = IsEmptyElement;
1035 ReadStartElement (localName, namespaceURI);
1037 return ValueAs (String.Empty, returnType, namespaceResolver, false);
1038 object obj = ReadContentAs (returnType, namespaceResolver);
1043 public virtual object ReadContentAs (Type returnType, IXmlNamespaceResolver namespaceResolver)
1045 return ValueAs (ReadContentString (), returnType, namespaceResolver, false);
1048 private object ValueAs (string text, Type type, IXmlNamespaceResolver resolver, bool isArrayItem)
1051 if (type == typeof (object))
1053 if (type.IsArray && !isArrayItem) {
1054 var elemType = type.GetElementType ();
1055 var sarr = text.Split ((string []) null, StringSplitOptions.RemoveEmptyEntries);
1056 var ret = Array.CreateInstance (elemType, sarr.Length);
1057 for (int i = 0; i < ret.Length; i++)
1058 ret.SetValue (ValueAs (sarr [i], elemType, resolver, true), i);
1062 if (type == typeof (XmlQualifiedName)) {
1063 if (resolver != null)
1064 return XmlQualifiedName.Parse (text, resolver, true);
1066 return XmlQualifiedName.Parse (text, this, true);
1068 if (type == typeof (Uri))
1069 return XmlConvert.ToUri (text);
1070 if (type == typeof (TimeSpan))
1071 return XmlConvert.ToTimeSpan (text);
1072 if (type == typeof (DateTimeOffset))
1073 return XmlConvert.ToDateTimeOffset (text);
1075 switch (Type.GetTypeCode (type)) {
1076 case TypeCode.Boolean:
1077 return XQueryConvert.StringToBoolean (text);
1079 return XmlConvert.ToByte (text);
1080 case TypeCode.SByte:
1081 return XmlConvert.ToSByte (text);
1082 case TypeCode.Int16:
1083 return XmlConvert.ToInt16 (text);
1084 case TypeCode.UInt16:
1085 return XQueryConvert.StringToUnsignedShort (text);
1086 case TypeCode.Int32:
1087 return XQueryConvert.StringToInt (text);
1088 case TypeCode.UInt32:
1089 return XQueryConvert.StringToUnsignedInt (text);
1090 case TypeCode.Int64:
1091 return XQueryConvert.StringToInteger (text);
1092 case TypeCode.UInt64:
1093 return XQueryConvert.StringToUnsignedLong (text);
1094 case TypeCode.DateTime:
1095 return XQueryConvert.StringToDateTime (text);
1096 case TypeCode.Decimal:
1097 return XQueryConvert.StringToDecimal (text);
1098 case TypeCode.Double:
1099 return XQueryConvert.StringToDouble (text);
1100 case TypeCode.Single:
1101 return XQueryConvert.StringToFloat (text);
1102 case TypeCode.String:
1105 } catch (Exception ex) {
1106 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);
1108 throw new XmlException (String.Format ("Specified type '{0}' is not supported.", type));
1111 public virtual bool ReadElementContentAsBoolean ()
1114 return XQueryConvert.StringToBoolean (ReadElementContentAsString ());
1115 } catch (FormatException ex) {
1116 throw XmlError ("Typed value is invalid.", ex);
1120 public virtual DateTime ReadElementContentAsDateTime ()
1123 return XQueryConvert.StringToDateTime (ReadElementContentAsString ());
1124 } catch (FormatException ex) {
1125 throw XmlError ("Typed value is invalid.", ex);
1129 public virtual decimal ReadElementContentAsDecimal ()
1132 return XQueryConvert.StringToDecimal (ReadElementContentAsString ());
1133 } catch (FormatException ex) {
1134 throw XmlError ("Typed value is invalid.", ex);
1138 public virtual double ReadElementContentAsDouble ()
1141 return XQueryConvert.StringToDouble (ReadElementContentAsString ());
1142 } catch (FormatException ex) {
1143 throw XmlError ("Typed value is invalid.", ex);
1147 public virtual float ReadElementContentAsFloat ()
1150 return XQueryConvert.StringToFloat (ReadElementContentAsString ());
1151 } catch (FormatException ex) {
1152 throw XmlError ("Typed value is invalid.", ex);
1156 public virtual int ReadElementContentAsInt ()
1159 return XQueryConvert.StringToInt (ReadElementContentAsString ());
1160 } catch (FormatException ex) {
1161 throw XmlError ("Typed value is invalid.", ex);
1165 public virtual long ReadElementContentAsLong ()
1168 return XQueryConvert.StringToInteger (ReadElementContentAsString ());
1169 } catch (FormatException ex) {
1170 throw XmlError ("Typed value is invalid.", ex);
1174 public virtual string ReadElementContentAsString ()
1176 bool isEmpty = IsEmptyElement;
1177 // unlike ReadStartElement() it rejects non-content nodes (this check is done before MoveToContent())
1178 if (NodeType != XmlNodeType.Element)
1179 throw new InvalidOperationException (String.Format ("'{0}' is an element node.", NodeType));
1180 ReadStartElement ();
1182 return String.Empty;
1183 string s = ReadContentString (false);
1188 public virtual bool ReadElementContentAsBoolean (string localName, string namespaceURI)
1191 return XQueryConvert.StringToBoolean (ReadElementContentAsString (localName, namespaceURI));
1192 } catch (FormatException ex) {
1193 throw XmlError ("Typed value is invalid.", ex);
1197 public virtual DateTime ReadElementContentAsDateTime (string localName, string namespaceURI)
1200 return XQueryConvert.StringToDateTime (ReadElementContentAsString (localName, namespaceURI));
1201 } catch (FormatException ex) {
1202 throw XmlError ("Typed value is invalid.", ex);
1206 public virtual decimal ReadElementContentAsDecimal (string localName, string namespaceURI)
1209 return XQueryConvert.StringToDecimal (ReadElementContentAsString (localName, namespaceURI));
1210 } catch (FormatException ex) {
1211 throw XmlError ("Typed value is invalid.", ex);
1215 public virtual double ReadElementContentAsDouble (string localName, string namespaceURI)
1218 return XQueryConvert.StringToDouble (ReadElementContentAsString (localName, namespaceURI));
1219 } catch (FormatException ex) {
1220 throw XmlError ("Typed value is invalid.", ex);
1224 public virtual float ReadElementContentAsFloat (string localName, string namespaceURI)
1227 return XQueryConvert.StringToFloat (ReadElementContentAsString (localName, namespaceURI));
1228 } catch (FormatException ex) {
1229 throw XmlError ("Typed value is invalid.", ex);
1233 public virtual int ReadElementContentAsInt (string localName, string namespaceURI)
1236 return XQueryConvert.StringToInt (ReadElementContentAsString (localName, namespaceURI));
1237 } catch (FormatException ex) {
1238 throw XmlError ("Typed value is invalid.", ex);
1242 public virtual long ReadElementContentAsLong (string localName, string namespaceURI)
1245 return XQueryConvert.StringToInteger (ReadElementContentAsString (localName, namespaceURI));
1246 } catch (FormatException ex) {
1247 throw XmlError ("Typed value is invalid.", ex);
1251 public virtual string ReadElementContentAsString (string localName, string namespaceURI)
1253 bool isEmpty = IsEmptyElement;
1254 // unlike ReadStartElement() it rejects non-content nodes (this check is done before MoveToContent())
1255 if (NodeType != XmlNodeType.Element)
1256 throw new InvalidOperationException (String.Format ("'{0}' is an element node.", NodeType));
1257 ReadStartElement (localName, namespaceURI);
1259 return String.Empty;
1260 string s = ReadContentString (false);
1265 public virtual bool ReadContentAsBoolean ()
1268 return XQueryConvert.StringToBoolean (ReadContentString ());
1269 } catch (FormatException ex) {
1270 throw XmlError ("Typed value is invalid.", ex);
1274 public virtual DateTime ReadContentAsDateTime ()
1277 return XQueryConvert.StringToDateTime (ReadContentString ());
1278 } catch (FormatException ex) {
1279 throw XmlError ("Typed value is invalid.", ex);
1283 public virtual decimal ReadContentAsDecimal ()
1286 return XQueryConvert.StringToDecimal (ReadContentString ());
1287 } catch (FormatException ex) {
1288 throw XmlError ("Typed value is invalid.", ex);
1292 public virtual double ReadContentAsDouble ()
1295 return XQueryConvert.StringToDouble (ReadContentString ());
1296 } catch (FormatException ex) {
1297 throw XmlError ("Typed value is invalid.", ex);
1301 public virtual float ReadContentAsFloat ()
1304 return XQueryConvert.StringToFloat (ReadContentString ());
1305 } catch (FormatException ex) {
1306 throw XmlError ("Typed value is invalid.", ex);
1310 public virtual int ReadContentAsInt ()
1313 return XQueryConvert.StringToInt (ReadContentString ());
1314 } catch (FormatException ex) {
1315 throw XmlError ("Typed value is invalid.", ex);
1319 public virtual long ReadContentAsLong ()
1322 return XQueryConvert.StringToInteger (ReadContentString ());
1323 } catch (FormatException ex) {
1324 throw XmlError ("Typed value is invalid.", ex);
1328 public virtual string ReadContentAsString ()
1330 return ReadContentString ();
1333 public virtual int ReadContentAsBase64 (
1334 byte [] buffer, int index, int count)
1337 return binary.ReadContentAsBase64 (
1338 buffer, index, count);
1341 public virtual int ReadContentAsBinHex (
1342 byte [] buffer, int index, int count)
1345 return binary.ReadContentAsBinHex (
1346 buffer, index, count);
1349 public virtual int ReadElementContentAsBase64 (
1350 byte [] buffer, int index, int count)
1353 return binary.ReadElementContentAsBase64 (
1354 buffer, index, count);
1357 public virtual int ReadElementContentAsBinHex (
1358 byte [] buffer, int index, int count)
1361 return binary.ReadElementContentAsBinHex (
1362 buffer, index, count);
1365 private void CheckSupport ()
1367 // Default implementation expects both.
1368 if (!CanReadBinaryContent || !CanReadValueChunk)
1369 throw new NotSupportedException ();
1371 binary = new XmlReaderBinarySupport (this);
1376 public virtual int ReadValueChunk (char [] buffer, int index, int count)
1378 if (!CanReadValueChunk)
1379 throw new NotSupportedException ();
1381 binary = new XmlReaderBinarySupport (this);
1382 return binary.ReadValueChunk (buffer, index, count);
1385 public abstract void ResolveEntity ();
1387 public virtual void Skip ()
1389 if (ReadState != ReadState.Interactive)
1393 if (NodeType != XmlNodeType.Element || IsEmptyElement) {
1399 while (Read () && depth < Depth)
1401 if (NodeType == XmlNodeType.EndElement)
1405 private XmlException XmlError (string message)
1407 return new XmlException (this as IXmlLineInfo, BaseURI, message);
1410 private XmlException XmlError (string message, Exception innerException)
1412 return new XmlException (this as IXmlLineInfo, BaseURI, message);
1418 #region .NET 4.5 Async Methods
1424 if (!settings.Async)
1425 throw new InvalidOperationException ("Set XmlReaderSettings.Async to true if you want to use Async Methods.");
1428 throw new InvalidOperationException ("An asynchronous operation is already in progress.");
1429 asyncRunning = true;
1433 public virtual Task<bool> ReadAsync ()
1436 return Task.Run (() => {
1440 asyncRunning = false;
1445 public virtual Task<string> GetValueAsync ()
1448 return Task.Run (() => {
1452 asyncRunning = false;
1457 public virtual Task<string> ReadInnerXmlAsync ()
1460 return Task.Run (() => {
1462 return ReadInnerXml ();
1464 asyncRunning = false;
1469 public virtual Task<string> ReadOuterXmlAsync ()
1472 return Task.Run (() => {
1474 return ReadOuterXml ();
1476 asyncRunning = false;
1481 public virtual Task<string> ReadContentAsStringAsync ()
1484 return Task.Run (() => {
1486 return ReadContentAsString ();
1488 asyncRunning = false;
1493 public virtual Task<int> ReadContentAsBase64Async (byte[] buffer, int index, int count)
1496 return Task.Run (() => {
1498 return ReadContentAsBase64 (buffer, index, count);
1500 asyncRunning = false;
1505 public virtual Task<int> ReadContentAsBinHexAsync (byte[] buffer, int index, int count)
1508 return Task.Run (() => {
1510 return ReadContentAsBinHex (buffer, index, count);
1512 asyncRunning = false;
1517 public virtual Task<int> ReadElementContentAsBase64Async (byte[] buffer, int index, int count)
1520 return Task.Run (() => {
1522 return ReadElementContentAsBase64 (buffer, index, count);
1524 asyncRunning = false;
1529 public virtual Task<int> ReadElementContentAsBinHexAsync (byte[] buffer, int index, int count)
1532 return Task.Run (() => {
1534 return ReadElementContentAsBinHex (buffer, index, count);
1536 asyncRunning = false;
1541 public virtual Task<int> ReadValueChunkAsync (char[] buffer, int index, int count)
1544 return Task.Run (() => {
1546 return ReadValueChunk (buffer, index, count);
1548 asyncRunning = false;
1553 public virtual Task<object> ReadContentAsAsync (Type returnType, IXmlNamespaceResolver namespaceResolver)
1556 return Task.Run (() => {
1558 return ReadContentAs (returnType, namespaceResolver);
1560 asyncRunning = false;
1565 public virtual Task<object> ReadContentAsObjectAsync ()
1568 return Task.Run (() => {
1570 return ReadContentAsObject ();
1572 asyncRunning = false;
1577 public virtual Task<object> ReadElementContentAsAsync (Type returnType, IXmlNamespaceResolver namespaceResolver)
1580 return Task.Run (() => {
1582 return ReadElementContentAs (returnType, namespaceResolver);
1584 asyncRunning = false;
1589 public virtual Task<object> ReadElementContentAsObjectAsync ()
1592 return Task.Run (() => {
1594 return ReadElementContentAsObject ();
1596 asyncRunning = false;
1601 public virtual Task<string> ReadElementContentAsStringAsync ()
1604 return Task.Run (() => {
1606 return ReadElementContentAsString ();
1608 asyncRunning = false;
1613 public virtual Task<XmlNodeType> MoveToContentAsync ()
1616 return Task.Run (() => {
1618 return MoveToContent ();
1620 asyncRunning = false;
1625 public virtual Task SkipAsync ()
1628 return Task.Run (() => {
1632 asyncRunning = false;