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;
39 using System.Xml.Schema; // only required for NET_2_0 (SchemaInfo)
40 using System.Xml.Serialization; // only required for NET_2_0 (SchemaInfo)
41 using Mono.Xml.Schema; // only required for NET_2_0
43 using Mono.Xml; // only required for NET_2_0
45 using System.Threading;
46 using System.Threading.Tasks;
52 public abstract class XmlReader : IDisposable
54 public abstract class XmlReader
57 private StringBuilder readStringBuffer;
58 private XmlReaderBinarySupport binary;
60 private XmlReaderSettings settings;
65 protected XmlReader ()
73 public abstract int AttributeCount { get; }
75 public abstract string BaseURI { get; }
77 internal XmlReaderBinarySupport Binary {
78 get { return binary; }
81 internal XmlReaderBinarySupport.CharGetter BinaryCharGetter {
82 get { return binary != null ? binary.Getter : null; }
85 binary = new XmlReaderBinarySupport (this);
86 binary.Getter = value;
91 // To enable it internally in sys.xml, just insert these
92 // two lines into Read():
95 // if (Binary != null)
99 public virtual bool CanReadBinaryContent {
100 get { return false; }
103 public virtual bool CanReadValueChunk {
104 get { return false; }
107 internal virtual bool CanReadBinaryContent {
108 get { return false; }
111 internal virtual bool CanReadValueChunk {
112 get { return false; }
116 public virtual bool CanResolveEntity
118 get { return false; }
121 public abstract int Depth { get; }
123 public abstract bool EOF { get; }
125 public virtual bool HasAttributes
127 get { return AttributeCount > 0; }
131 public virtual bool HasValue {
134 case XmlNodeType.Attribute:
135 case XmlNodeType.Comment:
136 case XmlNodeType.ProcessingInstruction:
137 case XmlNodeType.SignificantWhitespace:
138 case XmlNodeType.CDATA:
139 case XmlNodeType.Text:
140 case XmlNodeType.Whitespace:
141 case XmlNodeType.XmlDeclaration:
148 public abstract bool HasValue { get; }
151 public abstract bool IsEmptyElement { get; }
154 public virtual bool IsDefault {
155 get { return false; }
158 public virtual string this [int i] {
159 get { return GetAttribute (i); }
162 public virtual string this [string name] {
163 get { return GetAttribute (name); }
166 public virtual string this [string name, string namespaceURI] {
167 get { return GetAttribute (name, namespaceURI); }
170 public abstract bool IsDefault { get; }
172 public abstract string this [int i] { get; }
174 public abstract string this [string name] { get; }
176 public abstract string this [string localName, string namespaceName] { get; }
179 public abstract string LocalName { get; }
182 public virtual string Name {
184 return Prefix.Length > 0 ?
185 String.Concat (Prefix, ":", LocalName) :
190 public abstract string Name { get; }
193 public abstract string NamespaceURI { get; }
195 public abstract XmlNameTable NameTable { get; }
197 public abstract XmlNodeType NodeType { get; }
199 public abstract string Prefix { get; }
202 public virtual char QuoteChar {
206 public abstract char QuoteChar { get; }
209 public abstract ReadState ReadState { get; }
213 public virtual IXmlSchemaInfo SchemaInfo {
218 public virtual XmlReaderSettings Settings {
219 get { return settings; }
223 public abstract string Value { get; }
226 public virtual string XmlLang {
227 get { return String.Empty; }
230 public virtual XmlSpace XmlSpace {
231 get { return XmlSpace.None; }
234 public abstract string XmlLang { get; }
236 public abstract XmlSpace XmlSpace { get; }
244 public virtual void Close ()
247 throw new InvalidOperationException ("An asynchronous operation is already in progress.");
250 public abstract void Close ();
254 private static XmlNameTable PopulateNameTable (
255 XmlReaderSettings settings)
257 XmlNameTable nameTable = settings.NameTable;
258 if (nameTable == null)
259 nameTable = new NameTable ();
263 private static XmlParserContext PopulateParserContext (
264 XmlReaderSettings settings, string baseUri)
266 XmlNameTable nt = PopulateNameTable (settings);
267 return new XmlParserContext (nt,
268 new XmlNamespaceManager (nt),
279 private static XmlNodeType GetNodeType (
280 XmlReaderSettings settings)
282 ConformanceLevel level = settings != null ? settings.ConformanceLevel : ConformanceLevel.Auto;
284 level == ConformanceLevel.Fragment ?
285 XmlNodeType.Element :
286 XmlNodeType.Document;
289 public static XmlReader Create (Stream input)
291 return Create (input, null);
294 public static XmlReader Create (string inputUri)
296 return Create (inputUri, null);
299 public static XmlReader Create (TextReader input)
301 return Create (input, null);
304 public static XmlReader Create (string inputUri, XmlReaderSettings settings)
306 return Create (inputUri, settings, null);
309 public static XmlReader Create (Stream input, XmlReaderSettings settings)
311 return Create (input, settings, String.Empty);
314 public static XmlReader Create (TextReader input, XmlReaderSettings settings)
316 return Create (input, settings, String.Empty);
319 static XmlReaderSettings PopulateSettings (XmlReaderSettings src)
321 XmlReaderSettings copy;
323 copy = new XmlReaderSettings ();
332 static XmlReaderSettings PopulateSettings (XmlReader reader, XmlReaderSettings src)
334 XmlReaderSettings copy;
336 copy = new XmlReaderSettings ();
340 if (reader.Settings != null)
341 copy.Async = reader.Settings.Async;
347 public static XmlReader Create (Stream input, XmlReaderSettings settings, string baseUri)
349 settings = PopulateSettings (settings);
350 return Create (input, settings,
351 PopulateParserContext (settings, baseUri));
354 public static XmlReader Create (TextReader input, XmlReaderSettings settings, string baseUri)
356 settings = PopulateSettings (settings);
357 return Create (input, settings,
358 PopulateParserContext (settings, baseUri));
361 public static XmlReader Create (XmlReader reader, XmlReaderSettings settings)
363 settings = PopulateSettings (reader, settings);
364 XmlReader r = CreateFilteredXmlReader (reader, settings);
365 r.settings = settings;
369 public static XmlReader Create (string inputUri, XmlReaderSettings settings, XmlParserContext inputContext)
371 settings = PopulateSettings (settings);
372 bool closeInputBak = settings.CloseInput;
374 settings.CloseInput = true; // forced. See XmlReaderCommonTests.CreateFromUrlClose().
375 if (inputContext == null)
376 inputContext = PopulateParserContext (settings, inputUri);
377 XmlTextReader xtr = new XmlTextReader (false, settings.XmlResolver, inputUri, GetNodeType (settings), inputContext);
378 XmlReader ret = CreateCustomizedTextReader (xtr, settings);
381 settings.CloseInput = closeInputBak;
385 public static XmlReader Create (Stream input, XmlReaderSettings settings, XmlParserContext inputContext)
387 settings = PopulateSettings (settings);
388 if (inputContext == null)
389 inputContext = PopulateParserContext (settings, String.Empty);
390 return CreateCustomizedTextReader (new XmlTextReader (input, GetNodeType (settings), inputContext), settings);
393 public static XmlReader Create (TextReader input, XmlReaderSettings settings, XmlParserContext inputContext)
395 settings = PopulateSettings (settings);
396 if (inputContext == null)
397 inputContext = PopulateParserContext (settings, String.Empty);
398 return CreateCustomizedTextReader (new XmlTextReader (inputContext.BaseURI, input, GetNodeType (settings), inputContext), settings);
401 private static XmlReader CreateCustomizedTextReader (XmlTextReader reader, XmlReaderSettings settings)
403 reader.XmlResolver = settings.XmlResolver;
404 // Normalization is set true by default.
405 reader.Normalization = true;
406 reader.EntityHandling = EntityHandling.ExpandEntities;
408 if (settings.ProhibitDtd)
409 reader.ProhibitDtd = true;
411 if (!settings.CheckCharacters)
412 reader.CharacterChecking = false;
414 // I guess it might be changed in 2.0 RTM to set true
415 // as default, or just disappear. It goes against
416 // XmlTextReader's default usage and users will have
417 // to close input manually (that's annoying). Moreover,
418 // MS XmlTextReader consumes text input more than
419 // actually read and users can acquire those extra
420 // consumption by GetRemainder() that returns different
422 reader.CloseInput = settings.CloseInput;
424 // I would like to support it in detail later;
425 // MSDN description looks source of confusion. We don't
426 // need examples, but precise list of how it works.
427 reader.Conformance = settings.ConformanceLevel;
429 reader.AdjustLineInfoOffset (settings.LineNumberOffset,
430 settings.LinePositionOffset);
432 if (settings.NameTable != null)
433 reader.SetNameTable (settings.NameTable);
435 XmlReader r = CreateFilteredXmlReader (reader, settings);
436 r.settings = settings;
440 private static XmlReader CreateFilteredXmlReader (XmlReader reader, XmlReaderSettings settings)
442 ConformanceLevel conf = ConformanceLevel.Auto;
443 if (reader is XmlTextReader)
444 conf = ((XmlTextReader) reader).Conformance;
445 else if (reader.Settings != null)
446 conf = reader.Settings.ConformanceLevel;
448 conf = settings.ConformanceLevel;
449 if (settings.ConformanceLevel != ConformanceLevel.Auto &&
450 conf != settings.ConformanceLevel)
451 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));
452 settings.ConformanceLevel = conf;
454 reader = CreateValidatingXmlReader (reader, settings);
456 if ( settings.IgnoreComments ||
457 settings.IgnoreProcessingInstructions ||
458 settings.IgnoreWhitespace)
459 return new XmlFilterReader (reader, settings);
461 reader.settings = settings;
466 private static XmlReader CreateValidatingXmlReader (XmlReader reader, XmlReaderSettings settings)
471 XmlValidatingReader xvr = null;
472 switch (settings.ValidationType) {
473 // Auto and XDR are obsoleted in 2.0 and therefore ignored.
476 case ValidationType.DTD:
477 xvr = new XmlValidatingReader (reader);
478 xvr.XmlResolver = settings.XmlResolver;
479 xvr.ValidationType = ValidationType.DTD;
481 case ValidationType.Schema:
482 return new XmlSchemaValidatingReader (reader, settings);
485 // Actually I don't think they are treated in DTD validation though...
486 if ((settings.ValidationFlags & XmlSchemaValidationFlags.ProcessIdentityConstraints) == 0)
487 throw new NotImplementedException ();
488 //if ((settings.ValidationFlags & XmlSchemaValidationFlags.ProcessInlineSchema) != 0)
489 // throw new NotImplementedException ();
490 //if ((settings.ValidationFlags & XmlSchemaValidationFlags.ProcessSchemaLocation) != 0)
491 // throw new NotImplementedException ();
492 //if ((settings.ValidationFlags & XmlSchemaValidationFlags.ReportValidationWarnings) == 0)
493 // throw new NotImplementedException ();
495 return xvr != null ? xvr : reader;
499 #if NET_4_0 || MOBILE
500 public void Dispose ()
502 void IDisposable.Dispose()
508 protected virtual void Dispose (bool disposing)
510 if (ReadState != ReadState.Closed)
515 public abstract string GetAttribute (int i);
517 public abstract string GetAttribute (string name);
519 public abstract string GetAttribute (string name, string namespaceURI);
521 public static bool IsName (string str)
523 return str != null && XmlChar.IsName (str);
526 public static bool IsNameToken (string str)
528 return str != null && XmlChar.IsNmToken (str);
531 public virtual bool IsStartElement ()
533 return (MoveToContent () == XmlNodeType.Element);
536 public virtual bool IsStartElement (string name)
538 if (!IsStartElement ())
541 return (Name == name);
544 public virtual bool IsStartElement (string localname, string ns)
546 if (!IsStartElement ())
549 return (LocalName == localname && NamespaceURI == ns);
552 public abstract string LookupNamespace (string prefix);
555 public virtual void MoveToAttribute (int i)
557 if (i >= AttributeCount)
558 throw new ArgumentOutOfRangeException ();
559 MoveToFirstAttribute ();
560 for (int a = 0; a < i; a++)
561 MoveToNextAttribute ();
564 public abstract void MoveToAttribute (int i);
567 public abstract bool MoveToAttribute (string name);
569 public abstract bool MoveToAttribute (string name, string ns);
571 private bool IsContent (XmlNodeType nodeType)
574 * (non-white space text, CDATA, Element, EndElement, EntityReference, or EndEntity)
577 case XmlNodeType.Text:
579 case XmlNodeType.CDATA:
581 case XmlNodeType.Element:
583 case XmlNodeType.EndElement:
585 case XmlNodeType.EntityReference:
587 case XmlNodeType.EndEntity:
594 public virtual XmlNodeType MoveToContent ()
597 case ReadState.Initial:
598 case ReadState.Interactive:
604 if (NodeType == XmlNodeType.Attribute)
608 if (IsContent (NodeType))
612 return XmlNodeType.None;
615 public abstract bool MoveToElement ();
617 public abstract bool MoveToFirstAttribute ();
619 public abstract bool MoveToNextAttribute ();
621 public abstract bool Read ();
623 public abstract bool ReadAttributeValue ();
625 public virtual string ReadElementString ()
627 if (MoveToContent () != XmlNodeType.Element) {
628 string error = String.Format ("'{0}' is an invalid node type.",
629 NodeType.ToString ());
630 throw XmlError (error);
633 string result = String.Empty;
634 if (!IsEmptyElement) {
636 result = ReadString ();
637 if (NodeType != XmlNodeType.EndElement) {
638 string error = String.Format ("'{0}' is an invalid node type.",
639 NodeType.ToString ());
640 throw XmlError (error);
648 public virtual string ReadElementString (string name)
650 if (MoveToContent () != XmlNodeType.Element) {
651 string error = String.Format ("'{0}' is an invalid node type.",
652 NodeType.ToString ());
653 throw XmlError (error);
657 string error = String.Format ("The {0} tag from namespace {1} is expected.",
659 throw XmlError (error);
662 string result = String.Empty;
663 if (!IsEmptyElement) {
665 result = ReadString ();
666 if (NodeType != XmlNodeType.EndElement) {
667 string error = String.Format ("'{0}' is an invalid node type.",
668 NodeType.ToString ());
669 throw XmlError (error);
677 public virtual string ReadElementString (string localname, string ns)
679 if (MoveToContent () != XmlNodeType.Element) {
680 string error = String.Format ("'{0}' is an invalid node type.",
681 NodeType.ToString ());
682 throw XmlError (error);
685 if (localname != LocalName || NamespaceURI != ns) {
686 string error = String.Format ("The {0} tag from namespace {1} is expected.",
687 LocalName, NamespaceURI);
688 throw XmlError (error);
691 string result = String.Empty;
692 if (!IsEmptyElement) {
694 result = ReadString ();
695 if (NodeType != XmlNodeType.EndElement) {
696 string error = String.Format ("'{0}' is an invalid node type.",
697 NodeType.ToString ());
698 throw XmlError (error);
706 public virtual void ReadEndElement ()
708 if (MoveToContent () != XmlNodeType.EndElement) {
709 string error = String.Format ("'{0}' is an invalid node type.",
710 NodeType.ToString ());
711 throw XmlError (error);
717 public virtual string ReadInnerXml ()
719 if (ReadState != ReadState.Interactive || NodeType == XmlNodeType.EndElement)
722 if (IsEmptyElement) {
726 StringWriter sw = new StringWriter ();
727 XmlTextWriter xtw = new XmlTextWriter (sw);
728 if (NodeType == XmlNodeType.Element) {
729 int startDepth = Depth;
731 while (startDepth < Depth) {
732 if (ReadState != ReadState.Interactive)
733 throw XmlError ("Unexpected end of the XML reader.");
734 xtw.WriteNode (this, false);
736 // reader is now end element, then proceed once more.
740 xtw.WriteNode (this, false);
742 return sw.ToString ();
745 public virtual string ReadOuterXml ()
747 if (ReadState != ReadState.Interactive || NodeType == XmlNodeType.EndElement)
751 case XmlNodeType.Element:
752 case XmlNodeType.Attribute:
753 StringWriter sw = new StringWriter ();
754 XmlTextWriter xtw = new XmlTextWriter (sw);
755 xtw.WriteNode (this, false);
756 return sw.ToString ();
763 public virtual void ReadStartElement ()
765 if (MoveToContent () != XmlNodeType.Element) {
766 string error = String.Format ("'{0}' is an invalid node type.",
767 NodeType.ToString ());
768 throw XmlError (error);
774 public virtual void ReadStartElement (string name)
776 if (MoveToContent () != XmlNodeType.Element) {
777 string error = String.Format ("'{0}' is an invalid node type.",
778 NodeType.ToString ());
779 throw XmlError (error);
783 string error = String.Format ("The {0} tag from namespace {1} is expected.",
785 throw XmlError (error);
791 public virtual void ReadStartElement (string localname, string ns)
793 if (MoveToContent () != XmlNodeType.Element) {
794 string error = String.Format ("'{0}' is an invalid node type.",
795 NodeType.ToString ());
796 throw XmlError (error);
799 if (localname != LocalName || NamespaceURI != ns) {
800 string error = String.Format ("Expecting {0} tag from namespace {1}, got {2} and {3} instead",
802 LocalName, NamespaceURI);
803 throw XmlError (error);
809 public virtual string ReadString ()
811 if (readStringBuffer == null)
812 readStringBuffer = new StringBuilder ();
813 readStringBuffer.Length = 0;
820 case XmlNodeType.Element:
826 case XmlNodeType.Text:
827 case XmlNodeType.CDATA:
828 case XmlNodeType.Whitespace:
829 case XmlNodeType.SignificantWhitespace:
830 readStringBuffer.Append (Value);
836 case XmlNodeType.Text:
837 case XmlNodeType.CDATA:
838 case XmlNodeType.Whitespace:
839 case XmlNodeType.SignificantWhitespace:
842 case XmlNodeType.Text:
843 case XmlNodeType.CDATA:
844 case XmlNodeType.Whitespace:
845 case XmlNodeType.SignificantWhitespace:
846 readStringBuffer.Append (Value);
854 string ret = readStringBuffer.ToString ();
855 readStringBuffer.Length = 0;
860 public virtual Type ValueType {
861 get { return typeof (string); }
864 public virtual bool ReadToDescendant (string name)
866 if (ReadState == ReadState.Initial) {
868 if (IsStartElement (name))
871 if (NodeType != XmlNodeType.Element || IsEmptyElement)
874 for (Read (); depth < Depth; Read ())
875 if (NodeType == XmlNodeType.Element && name == Name)
880 public virtual bool ReadToDescendant (string localName, string namespaceURI)
882 if (ReadState == ReadState.Initial) {
884 if (IsStartElement (localName, namespaceURI))
887 if (NodeType != XmlNodeType.Element || IsEmptyElement)
890 for (Read (); depth < Depth; Read ())
891 if (NodeType == XmlNodeType.Element && localName == LocalName && namespaceURI == NamespaceURI)
896 public virtual bool ReadToFollowing (string name)
899 if (NodeType == XmlNodeType.Element && name == Name)
904 public virtual bool ReadToFollowing (string localName, string namespaceURI)
907 if (NodeType == XmlNodeType.Element && localName == LocalName && namespaceURI == NamespaceURI)
912 public virtual bool ReadToNextSibling (string name)
914 if (ReadState != ReadState.Interactive)
919 for (; !EOF && depth <= Depth; Skip ())
920 if (NodeType == XmlNodeType.Element && name == Name)
925 public virtual bool ReadToNextSibling (string localName, string namespaceURI)
927 if (ReadState != ReadState.Interactive)
931 for (; !EOF && depth <= Depth; Skip ())
932 if (NodeType == XmlNodeType.Element && localName == LocalName && namespaceURI == NamespaceURI)
937 public virtual XmlReader ReadSubtree ()
939 if (NodeType != XmlNodeType.Element)
940 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 ()));
941 return new SubtreeXmlReader (this);
944 private string ReadContentString ()
946 // The latter condition indicates that this XmlReader is on an attribute value
947 // (HasAttributes is to indicate it is on attribute value).
948 if (NodeType == XmlNodeType.Attribute || NodeType != XmlNodeType.Element && HasAttributes)
950 return ReadContentString (true);
953 private string ReadContentString (bool isText)
957 case XmlNodeType.Text:
958 case XmlNodeType.SignificantWhitespace:
959 case XmlNodeType.Whitespace:
960 case XmlNodeType.CDATA:
962 case XmlNodeType.Element:
963 throw new InvalidOperationException (String.Format ("Node type {0} is not supported in this operation.{1}", NodeType, GetLocation ()));
969 string value = String.Empty;
972 case XmlNodeType.Element:
975 throw XmlError ("Child element is not expected in this operation.");
976 case XmlNodeType.EndElement:
978 case XmlNodeType.Text:
979 case XmlNodeType.CDATA:
980 case XmlNodeType.SignificantWhitespace:
981 case XmlNodeType.Whitespace:
986 throw XmlError ("Unexpected end of document.");
989 string GetLocation ()
991 IXmlLineInfo li = this as IXmlLineInfo;
992 return li != null && li.HasLineInfo () ?
993 String.Format (" {0} (line {1}, column {2})", BaseURI, li.LineNumber, li.LinePosition) : String.Empty;
997 public virtual object ReadElementContentAsObject ()
999 return ReadElementContentAs (ValueType, null);
1003 public virtual object ReadElementContentAsObject (string localName, string namespaceURI)
1005 return ReadElementContentAs (ValueType, null, localName, namespaceURI);
1009 public virtual object ReadContentAsObject ()
1011 return ReadContentAs (ValueType, null);
1015 public virtual DateTimeOffset ReadContentAsDateTimeOffset ()
1017 return XmlConvert.ToDateTimeOffset (ReadContentString ());
1021 public virtual object ReadElementContentAs (Type returnType, IXmlNamespaceResolver namespaceResolver)
1023 bool isEmpty = IsEmptyElement;
1024 ReadStartElement ();
1025 object obj = ValueAs (isEmpty ? String.Empty : ReadContentString (false), returnType, namespaceResolver, false);
1031 public virtual object ReadElementContentAs (Type returnType, IXmlNamespaceResolver namespaceResolver, string localName, string namespaceURI)
1033 bool isEmpty = IsEmptyElement;
1034 ReadStartElement (localName, namespaceURI);
1036 return ValueAs (String.Empty, returnType, namespaceResolver, false);
1037 object obj = ReadContentAs (returnType, namespaceResolver);
1042 public virtual object ReadContentAs (Type returnType, IXmlNamespaceResolver namespaceResolver)
1044 return ValueAs (ReadContentString (), returnType, namespaceResolver, false);
1047 private object ValueAs (string text, Type type, IXmlNamespaceResolver resolver, bool isArrayItem)
1050 if (type == typeof (object))
1052 if (type.IsArray && !isArrayItem) {
1053 var elemType = type.GetElementType ();
1054 var sarr = text.Split ((string []) null, StringSplitOptions.RemoveEmptyEntries);
1055 var ret = Array.CreateInstance (elemType, sarr.Length);
1056 for (int i = 0; i < ret.Length; i++)
1057 ret.SetValue (ValueAs (sarr [i], elemType, resolver, true), i);
1061 if (type == typeof (XmlQualifiedName)) {
1062 if (resolver != null)
1063 return XmlQualifiedName.Parse (text, resolver, true);
1065 return XmlQualifiedName.Parse (text, this, true);
1067 if (type == typeof (Uri))
1068 return XmlConvert.ToUri (text);
1069 if (type == typeof (TimeSpan))
1070 return XmlConvert.ToTimeSpan (text);
1071 if (type == typeof (DateTimeOffset))
1072 return XmlConvert.ToDateTimeOffset (text);
1074 switch (Type.GetTypeCode (type)) {
1075 case TypeCode.Boolean:
1076 return XQueryConvert.StringToBoolean (text);
1077 case TypeCode.DateTime:
1078 return XQueryConvert.StringToDateTime (text);
1079 case TypeCode.Decimal:
1080 return XQueryConvert.StringToDecimal (text);
1081 case TypeCode.Double:
1082 return XQueryConvert.StringToDouble (text);
1083 case TypeCode.Int32:
1084 return XQueryConvert.StringToInt (text);
1085 case TypeCode.Int64:
1086 return XQueryConvert.StringToInteger (text);
1087 case TypeCode.Single:
1088 return XQueryConvert.StringToFloat (text);
1089 case TypeCode.String:
1092 } catch (Exception ex) {
1093 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);
1095 throw new ArgumentException (String.Format ("Specified type '{0}' is not supported.", type));
1098 public virtual bool ReadElementContentAsBoolean ()
1101 return XQueryConvert.StringToBoolean (ReadElementContentAsString ());
1102 } catch (FormatException ex) {
1103 throw XmlError ("Typed value is invalid.", ex);
1107 public virtual DateTime ReadElementContentAsDateTime ()
1110 return XQueryConvert.StringToDateTime (ReadElementContentAsString ());
1111 } catch (FormatException ex) {
1112 throw XmlError ("Typed value is invalid.", ex);
1116 public virtual decimal ReadElementContentAsDecimal ()
1119 return XQueryConvert.StringToDecimal (ReadElementContentAsString ());
1120 } catch (FormatException ex) {
1121 throw XmlError ("Typed value is invalid.", ex);
1125 public virtual double ReadElementContentAsDouble ()
1128 return XQueryConvert.StringToDouble (ReadElementContentAsString ());
1129 } catch (FormatException ex) {
1130 throw XmlError ("Typed value is invalid.", ex);
1134 public virtual float ReadElementContentAsFloat ()
1137 return XQueryConvert.StringToFloat (ReadElementContentAsString ());
1138 } catch (FormatException ex) {
1139 throw XmlError ("Typed value is invalid.", ex);
1143 public virtual int ReadElementContentAsInt ()
1146 return XQueryConvert.StringToInt (ReadElementContentAsString ());
1147 } catch (FormatException ex) {
1148 throw XmlError ("Typed value is invalid.", ex);
1152 public virtual long ReadElementContentAsLong ()
1155 return XQueryConvert.StringToInteger (ReadElementContentAsString ());
1156 } catch (FormatException ex) {
1157 throw XmlError ("Typed value is invalid.", ex);
1161 public virtual string ReadElementContentAsString ()
1163 bool isEmpty = IsEmptyElement;
1164 // unlike ReadStartElement() it rejects non-content nodes (this check is done before MoveToContent())
1165 if (NodeType != XmlNodeType.Element)
1166 throw new InvalidOperationException (String.Format ("'{0}' is an element node.", NodeType));
1167 ReadStartElement ();
1169 return String.Empty;
1170 string s = ReadContentString (false);
1175 public virtual bool ReadElementContentAsBoolean (string localName, string namespaceURI)
1178 return XQueryConvert.StringToBoolean (ReadElementContentAsString (localName, namespaceURI));
1179 } catch (FormatException ex) {
1180 throw XmlError ("Typed value is invalid.", ex);
1184 public virtual DateTime ReadElementContentAsDateTime (string localName, string namespaceURI)
1187 return XQueryConvert.StringToDateTime (ReadElementContentAsString (localName, namespaceURI));
1188 } catch (FormatException ex) {
1189 throw XmlError ("Typed value is invalid.", ex);
1193 public virtual decimal ReadElementContentAsDecimal (string localName, string namespaceURI)
1196 return XQueryConvert.StringToDecimal (ReadElementContentAsString (localName, namespaceURI));
1197 } catch (FormatException ex) {
1198 throw XmlError ("Typed value is invalid.", ex);
1202 public virtual double ReadElementContentAsDouble (string localName, string namespaceURI)
1205 return XQueryConvert.StringToDouble (ReadElementContentAsString (localName, namespaceURI));
1206 } catch (FormatException ex) {
1207 throw XmlError ("Typed value is invalid.", ex);
1211 public virtual float ReadElementContentAsFloat (string localName, string namespaceURI)
1214 return XQueryConvert.StringToFloat (ReadElementContentAsString (localName, namespaceURI));
1215 } catch (FormatException ex) {
1216 throw XmlError ("Typed value is invalid.", ex);
1220 public virtual int ReadElementContentAsInt (string localName, string namespaceURI)
1223 return XQueryConvert.StringToInt (ReadElementContentAsString (localName, namespaceURI));
1224 } catch (FormatException ex) {
1225 throw XmlError ("Typed value is invalid.", ex);
1229 public virtual long ReadElementContentAsLong (string localName, string namespaceURI)
1232 return XQueryConvert.StringToInteger (ReadElementContentAsString (localName, namespaceURI));
1233 } catch (FormatException ex) {
1234 throw XmlError ("Typed value is invalid.", ex);
1238 public virtual string ReadElementContentAsString (string localName, string namespaceURI)
1240 bool isEmpty = IsEmptyElement;
1241 // unlike ReadStartElement() it rejects non-content nodes (this check is done before MoveToContent())
1242 if (NodeType != XmlNodeType.Element)
1243 throw new InvalidOperationException (String.Format ("'{0}' is an element node.", NodeType));
1244 ReadStartElement (localName, namespaceURI);
1246 return String.Empty;
1247 string s = ReadContentString (false);
1252 public virtual bool ReadContentAsBoolean ()
1255 return XQueryConvert.StringToBoolean (ReadContentString ());
1256 } catch (FormatException ex) {
1257 throw XmlError ("Typed value is invalid.", ex);
1261 public virtual DateTime ReadContentAsDateTime ()
1264 return XQueryConvert.StringToDateTime (ReadContentString ());
1265 } catch (FormatException ex) {
1266 throw XmlError ("Typed value is invalid.", ex);
1270 public virtual decimal ReadContentAsDecimal ()
1273 return XQueryConvert.StringToDecimal (ReadContentString ());
1274 } catch (FormatException ex) {
1275 throw XmlError ("Typed value is invalid.", ex);
1279 public virtual double ReadContentAsDouble ()
1282 return XQueryConvert.StringToDouble (ReadContentString ());
1283 } catch (FormatException ex) {
1284 throw XmlError ("Typed value is invalid.", ex);
1288 public virtual float ReadContentAsFloat ()
1291 return XQueryConvert.StringToFloat (ReadContentString ());
1292 } catch (FormatException ex) {
1293 throw XmlError ("Typed value is invalid.", ex);
1297 public virtual int ReadContentAsInt ()
1300 return XQueryConvert.StringToInt (ReadContentString ());
1301 } catch (FormatException ex) {
1302 throw XmlError ("Typed value is invalid.", ex);
1306 public virtual long ReadContentAsLong ()
1309 return XQueryConvert.StringToInteger (ReadContentString ());
1310 } catch (FormatException ex) {
1311 throw XmlError ("Typed value is invalid.", ex);
1315 public virtual string ReadContentAsString ()
1317 return ReadContentString ();
1320 public virtual int ReadContentAsBase64 (
1321 byte [] buffer, int index, int count)
1324 return binary.ReadContentAsBase64 (
1325 buffer, index, count);
1328 public virtual int ReadContentAsBinHex (
1329 byte [] buffer, int index, int count)
1332 return binary.ReadContentAsBinHex (
1333 buffer, index, count);
1336 public virtual int ReadElementContentAsBase64 (
1337 byte [] buffer, int index, int count)
1340 return binary.ReadElementContentAsBase64 (
1341 buffer, index, count);
1344 public virtual int ReadElementContentAsBinHex (
1345 byte [] buffer, int index, int count)
1348 return binary.ReadElementContentAsBinHex (
1349 buffer, index, count);
1352 private void CheckSupport ()
1354 // Default implementation expects both.
1355 if (!CanReadBinaryContent || !CanReadValueChunk)
1356 throw new NotSupportedException ();
1358 binary = new XmlReaderBinarySupport (this);
1363 public virtual int ReadValueChunk (char [] buffer, int index, int count)
1365 if (!CanReadValueChunk)
1366 throw new NotSupportedException ();
1368 binary = new XmlReaderBinarySupport (this);
1369 return binary.ReadValueChunk (buffer, index, count);
1372 public abstract void ResolveEntity ();
1374 public virtual void Skip ()
1376 if (ReadState != ReadState.Interactive)
1380 if (NodeType != XmlNodeType.Element || IsEmptyElement) {
1386 while (Read () && depth < Depth)
1388 if (NodeType == XmlNodeType.EndElement)
1392 private XmlException XmlError (string message)
1394 return new XmlException (this as IXmlLineInfo, BaseURI, message);
1397 private XmlException XmlError (string message, Exception innerException)
1399 return new XmlException (this as IXmlLineInfo, BaseURI, message);
1405 #region .NET 4.5 Async Methods
1411 if (!settings.Async)
1412 throw new InvalidOperationException ("Set XmlReaderSettings.Async to true if you want to use Async Methods.");
1415 throw new InvalidOperationException ("An asynchronous operation is already in progress.");
1416 asyncRunning = true;
1420 public virtual Task<bool> ReadAsync ()
1423 return Task.Run (() => {
1427 asyncRunning = false;
1432 public virtual Task<string> GetValueAsync ()
1435 return Task.Run (() => {
1439 asyncRunning = false;
1444 public virtual Task<string> ReadInnerXmlAsync ()
1447 return Task.Run (() => {
1449 return ReadInnerXml ();
1451 asyncRunning = false;
1456 public virtual Task<string> ReadOuterXmlAsync ()
1459 return Task.Run (() => {
1461 return ReadOuterXml ();
1463 asyncRunning = false;
1468 public virtual Task<string> ReadContentAsStringAsync ()
1471 return Task.Run (() => {
1473 return ReadContentAsString ();
1475 asyncRunning = false;
1480 public virtual Task<int> ReadContentAsBase64Async (byte[] buffer, int index, int count)
1483 return Task.Run (() => {
1485 return ReadContentAsBase64 (buffer, index, count);
1487 asyncRunning = false;
1492 public virtual Task<int> ReadContentAsBinHexAsync (byte[] buffer, int index, int count)
1495 return Task.Run (() => {
1497 return ReadContentAsBinHex (buffer, index, count);
1499 asyncRunning = false;
1504 public virtual Task<int> ReadElementContentAsBase64Async (byte[] buffer, int index, int count)
1507 return Task.Run (() => {
1509 return ReadElementContentAsBase64 (buffer, index, count);
1511 asyncRunning = false;
1516 public virtual Task<int> ReadElementContentAsBinHexAsync (byte[] buffer, int index, int count)
1519 return Task.Run (() => {
1521 return ReadElementContentAsBinHex (buffer, index, count);
1523 asyncRunning = false;
1528 public virtual Task<int> ReadValueChunkAsync (char[] buffer, int index, int count)
1531 return Task.Run (() => {
1533 return ReadValueChunk (buffer, index, count);
1535 asyncRunning = false;
1540 public virtual Task<object> ReadContentAsAsync (Type returnType, IXmlNamespaceResolver namespaceResolver)
1543 return Task.Run (() => {
1545 return ReadContentAs (returnType, namespaceResolver);
1547 asyncRunning = false;
1552 public virtual Task<object> ReadContentAsObjectAsync ()
1555 return Task.Run (() => {
1557 return ReadContentAsObject ();
1559 asyncRunning = false;
1564 public virtual Task<object> ReadElementContentAsAsync (Type returnType, IXmlNamespaceResolver namespaceResolver)
1567 return Task.Run (() => {
1569 return ReadElementContentAs (returnType, namespaceResolver);
1571 asyncRunning = false;
1576 public virtual Task<object> ReadElementContentAsObjectAsync ()
1579 return Task.Run (() => {
1581 return ReadElementContentAsObject ();
1583 asyncRunning = false;
1588 public virtual Task<string> ReadElementContentAsStringAsync ()
1591 return Task.Run (() => {
1593 return ReadElementContentAsString ();
1595 asyncRunning = false;
1600 public virtual Task<XmlNodeType> MoveToContentAsync ()
1603 return Task.Run (() => {
1605 return MoveToContent ();
1607 asyncRunning = false;
1612 public virtual Task SkipAsync ()
1615 return Task.Run (() => {
1619 asyncRunning = false;