2006-10-27 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.XML / System.Xml / XmlReader.cs
1 //
2 // XmlReader.cs
3 //
4 // Authors:
5 //      Jason Diamond (jason@injektilo.org)
6 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 //      Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
8 //
9 // (C) 2001, 2002 Jason Diamond  http://injektilo.org/
10 // (c) 2002 Ximian, Inc. (http://www.ximian.com)
11 // (C) 2003 Atsushi Enomoto
12 //
13
14 //
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:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
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.
33 //
34 using System.Collections;
35 using System.Diagnostics;
36 using System.IO;
37 using System.Text;
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; // only required for NET_2_0
41 using Mono.Xml.Schema; // only required for NET_2_0
42
43 namespace System.Xml
44 {
45 #if NET_2_0
46         public abstract class XmlReader : IDisposable
47 #else
48         public abstract class XmlReader
49 #endif
50         {
51                 private StringBuilder readStringBuffer;
52                 private XmlReaderBinarySupport binary;
53 #if NET_2_0
54                 private XmlReaderSettings settings;
55 #endif
56
57                 #region Constructor
58
59                 protected XmlReader ()
60                 {
61                 }
62
63                 #endregion
64
65                 #region Properties
66
67                 public abstract int AttributeCount { get; }
68
69                 public abstract string BaseURI { get; }
70
71                 internal XmlReaderBinarySupport Binary {
72                         get { return binary; }
73                 }
74
75                 internal XmlReaderBinarySupport.CharGetter BinaryCharGetter {
76                         get { return binary != null ? binary.Getter : null; }
77                         set {
78                                 if (binary == null)
79                                         binary = new XmlReaderBinarySupport (this);
80                                 binary.Getter = value;
81                         }
82                 }
83
84 #if NET_2_0
85                 // To enable it internally in sys.xml, just insert these
86                 // two lines into Read():
87                 //
88                 //      #if NET_2_0
89                 //      if (Binary != null)
90                 //              Binary.Reset ();
91                 //      #endif
92                 //
93                 public virtual bool CanReadBinaryContent {
94                         get { return false; }
95                 }
96
97                 public virtual bool CanReadValueChunk {
98                         get { return false; }
99                 }
100 #else
101                 internal virtual bool CanReadBinaryContent {
102                         get { return false; }
103                 }
104
105                 internal virtual bool CanReadValueChunk {
106                         get { return false; }
107                 }
108 #endif
109
110                 public virtual bool CanResolveEntity
111                 {
112                         get     { return false; }
113                 }
114
115                 public abstract int Depth { get; }
116
117                 public abstract bool EOF { get; }
118
119                 public virtual bool HasAttributes
120                 {
121                         get { return AttributeCount > 0; }
122                 }
123
124                 public abstract bool HasValue { get; }
125
126                 public abstract bool IsEmptyElement { get; }
127
128 #if NET_2_0
129                 public virtual bool IsDefault {
130                         get { return false; }
131                 }
132
133                 public virtual string this [int i] {
134                         get { return GetAttribute (i); }
135                 }
136
137                 public virtual string this [string name] {
138                         get { return GetAttribute (name); }
139                 }
140
141                 public virtual string this [string name, string namespaceURI] {
142                         get { return GetAttribute (name, namespaceURI); }
143                 }
144 #else
145                 public abstract bool IsDefault { get; }
146
147                 public abstract string this [int i] { get; }
148
149                 public abstract string this [string name] { get; }
150
151                 public abstract string this [string localName, string namespaceName] { get; }
152 #endif
153
154                 public abstract string LocalName { get; }
155
156 #if NET_2_0
157                 public virtual string Name {
158                         get {
159                                 return Prefix.Length > 0 ?
160                                         String.Concat (Prefix, ":", LocalName) :
161                                         LocalName;
162                         }
163                 }
164 #else
165                 public abstract string Name { get; }
166 #endif
167
168                 public abstract string NamespaceURI { get; }
169
170                 public abstract XmlNameTable NameTable { get; }
171
172                 public abstract XmlNodeType NodeType { get; }
173
174                 public abstract string Prefix { get; }
175
176 #if NET_2_0
177                 public virtual char QuoteChar {
178                         get { return '\"'; }
179                 }
180 #else
181                 public abstract char QuoteChar { get; }
182 #endif
183
184                 public abstract ReadState ReadState { get; }
185
186 #if NET_2_0
187                 public virtual IXmlSchemaInfo SchemaInfo {
188                         get { return null; }
189                 }
190
191                 public virtual XmlReaderSettings Settings {
192                         get { return settings; }
193                 }
194 #endif
195
196                 public abstract string Value { get; }
197
198 #if NET_2_0
199                 public virtual string XmlLang {
200                         get { return String.Empty; }
201                 }
202
203                 public virtual XmlSpace XmlSpace {
204                         get { return XmlSpace.None; }
205                 }
206 #else
207                 public abstract string XmlLang { get; }
208
209                 public abstract XmlSpace XmlSpace { get; }
210 #endif
211
212                 #endregion
213
214                 #region Methods
215
216                 public abstract void Close ();
217
218 #if NET_2_0
219                 private static XmlNameTable PopulateNameTable (
220                         XmlReaderSettings settings)
221                 {
222                         XmlNameTable nameTable = settings.NameTable;
223                         if (nameTable == null)
224                                 nameTable = new NameTable ();
225                         return nameTable;
226                 }
227
228                 private static XmlParserContext PopulateParserContext (
229                         XmlReaderSettings settings, string baseUri)
230                 {
231                         XmlNameTable nt = PopulateNameTable (settings);
232                         return new XmlParserContext (nt,
233                                 new XmlNamespaceManager (nt),
234                                 baseUri,
235                                 XmlSpace.None);
236                 }
237
238                 private static XmlNodeType GetNodeType (
239                         XmlReaderSettings settings)
240                 {
241                         ConformanceLevel level = settings != null ? settings.ConformanceLevel : ConformanceLevel.Auto;
242                         return
243                                 level == ConformanceLevel.Fragment ?
244                                 XmlNodeType.Element :
245                                 XmlNodeType.Document;
246                 }
247
248                 public static XmlReader Create (Stream stream)
249                 {
250                         return Create (stream, null);
251                 }
252
253                 public static XmlReader Create (string url)
254                 {
255                         return Create (url, null);
256                 }
257
258                 public static XmlReader Create (TextReader reader)
259                 {
260                         return Create (reader, null);
261                 }
262
263                 public static XmlReader Create (string url, XmlReaderSettings settings)
264                 {
265                         return Create (url, settings, null);
266                 }
267
268                 public static XmlReader Create (Stream stream, XmlReaderSettings settings)
269                 {
270                         return Create (stream, settings, String.Empty);
271                 }
272
273                 public static XmlReader Create (TextReader reader, XmlReaderSettings settings)
274                 {
275                         return Create (reader, settings, String.Empty);
276                 }
277
278                 static XmlReaderSettings PopulateSettings (XmlReaderSettings src)
279                 {
280                         if (src == null)
281                                 return new XmlReaderSettings ();
282                         else
283                                 return src.Clone ();
284                 }
285
286                 public static XmlReader Create (Stream stream, XmlReaderSettings settings, string baseUri)
287                 {
288                         settings = PopulateSettings (settings);
289                         return Create (stream, settings,
290                                 PopulateParserContext (settings, baseUri));
291                 }
292
293                 public static XmlReader Create (TextReader reader, XmlReaderSettings settings, string baseUri)
294                 {
295                         settings = PopulateSettings (settings);
296                         return Create (reader, settings,
297                                 PopulateParserContext (settings, baseUri));
298                 }
299
300                 public static XmlReader Create (XmlReader reader, XmlReaderSettings settings)
301                 {
302                         settings = PopulateSettings (settings);
303                         XmlReader r = CreateFilteredXmlReader (reader, settings);
304                         r.settings = settings;
305                         return r;
306                 }
307
308                 public static XmlReader Create (string url, XmlReaderSettings settings, XmlParserContext context)
309                 {
310                         settings = PopulateSettings (settings);
311                         if (context == null)
312                                 context = PopulateParserContext (settings, url);
313                         XmlTextReader xtr = new XmlTextReader (true, url, GetNodeType (settings), context);
314                         XmlReader ret = CreateCustomizedTextReader (xtr, settings);
315                         xtr.CloseInput = true;
316                         return xtr;
317                 }
318
319                 public static XmlReader Create (Stream stream, XmlReaderSettings settings, XmlParserContext context)
320                 {
321                         settings = PopulateSettings (settings);
322                         if (context == null)
323                                 context = PopulateParserContext (settings, String.Empty);
324                         return CreateCustomizedTextReader (new XmlTextReader (stream, GetNodeType (settings), context), settings);
325                 }
326
327                 public static XmlReader Create (TextReader reader, XmlReaderSettings settings, XmlParserContext context)
328                 {
329                         settings = PopulateSettings (settings);
330                         if (context == null)
331                                 context = PopulateParserContext (settings, String.Empty);
332                         return CreateCustomizedTextReader (new XmlTextReader (context.BaseURI, reader, GetNodeType (settings), context), settings);
333                 }
334
335                 private static XmlReader CreateCustomizedTextReader (XmlTextReader reader, XmlReaderSettings settings)
336                 {
337                         reader.XmlResolver = settings.XmlResolver;
338                         // Normalization is set true by default.
339                         reader.Normalization = true;
340
341                         if (settings.ProhibitDtd)
342                                 reader.ProhibitDtd = true;
343
344                         if (!settings.CheckCharacters)
345                                 reader.CharacterChecking = false;
346
347                         // I guess it might be changed in 2.0 RTM to set true
348                         // as default, or just disappear. It goes against
349                         // XmlTextReader's default usage and users will have 
350                         // to close input manually (that's annoying). Moreover,
351                         // MS XmlTextReader consumes text input more than 
352                         // actually read and users can acquire those extra
353                         // consumption by GetRemainder() that returns different
354                         // TextReader.
355                         reader.CloseInput = settings.CloseInput;
356
357                         // I would like to support it in detail later;
358                         // MSDN description looks source of confusion. We don't
359                         // need examples, but precise list of how it works.
360                         reader.Conformance = settings.ConformanceLevel;
361
362                         reader.AdjustLineInfoOffset (settings.LineNumberOffset,
363                                 settings.LinePositionOffset);
364
365                         if (settings.NameTable != null)
366                                 reader.SetNameTable (settings.NameTable);
367
368                         XmlReader r = CreateFilteredXmlReader (reader, settings);
369                         r.settings = settings;
370                         return r;
371                 }
372
373                 private static XmlReader CreateFilteredXmlReader (XmlReader reader, XmlReaderSettings settings)
374                 {
375                         ConformanceLevel conf = ConformanceLevel.Auto;
376                         if (reader is XmlTextReader)
377                                 conf = ((XmlTextReader) reader).Conformance;
378                         else if (reader.Settings != null)
379                                 conf = reader.Settings.ConformanceLevel;
380                         else
381                                 conf = settings.ConformanceLevel;
382                         if (settings.ConformanceLevel != ConformanceLevel.Auto &&
383                                 conf != settings.ConformanceLevel)
384                                 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));
385                         settings.ConformanceLevel = conf;
386
387                         reader = CreateValidatingXmlReader (reader, settings);
388
389                         if (reader.Settings != null ||
390                                 settings.IgnoreComments ||
391                                 settings.IgnoreProcessingInstructions ||
392                                 settings.IgnoreWhitespace)
393                                 return new XmlFilterReader (reader, settings);
394                         else {
395                                 reader.settings = settings;
396                                 return reader;
397                         }
398                 }
399
400                 private static XmlReader CreateValidatingXmlReader (XmlReader reader, XmlReaderSettings settings)
401                 {
402                         XmlValidatingReader xvr = null;
403                         switch (settings.ValidationType) {
404                         // Auto and XDR are obsoleted in 2.0 and therefore ignored.
405                         default:
406                                 return reader;
407                         case ValidationType.DTD:
408                                 xvr = new XmlValidatingReader (reader);
409                                 xvr.XmlResolver = settings.XmlResolver;
410                                 xvr.ValidationType = ValidationType.DTD;
411                                 break;
412                         case ValidationType.Schema:
413                                 return new XmlSchemaValidatingReader (reader, settings);
414                         }
415
416                         // Actually I don't think they are treated in DTD validation though...
417                         if ((settings.ValidationFlags & XmlSchemaValidationFlags.ProcessIdentityConstraints) == 0)
418                                 throw new NotImplementedException ();
419                         //if ((settings.ValidationFlags & XmlSchemaValidationFlags.ProcessInlineSchema) != 0)
420                         //      throw new NotImplementedException ();
421                         //if ((settings.ValidationFlags & XmlSchemaValidationFlags.ProcessSchemaLocation) != 0)
422                         //      throw new NotImplementedException ();
423                         //if ((settings.ValidationFlags & XmlSchemaValidationFlags.ReportValidationWarnings) == 0)
424                         //      throw new NotImplementedException ();
425
426                         return xvr != null ? xvr : reader;
427                 }
428 #endif
429
430 #if NET_2_0
431                 void IDisposable.Dispose ()
432                 {
433                         Dispose (false);
434                 }
435
436                 protected virtual void Dispose (bool disposing)
437                 {
438                         if (ReadState != ReadState.Closed)
439                                 Close ();
440                 }
441 #endif
442
443                 public abstract string GetAttribute (int i);
444
445                 public abstract string GetAttribute (string name);
446
447                 public abstract string GetAttribute (
448                         string localName,
449                         string namespaceName);
450
451                 public static bool IsName (string s)
452                 {
453                         return s != null && XmlChar.IsName (s);
454                 }
455
456                 public static bool IsNameToken (string s)
457                 {
458                         return s != null && XmlChar.IsNmToken (s);
459                 }
460
461                 public virtual bool IsStartElement ()
462                 {
463                         return (MoveToContent () == XmlNodeType.Element);
464                 }
465
466                 public virtual bool IsStartElement (string name)
467                 {
468                         if (!IsStartElement ())
469                                 return false;
470
471                         return (Name == name);
472                 }
473
474                 public virtual bool IsStartElement (string localName, string namespaceName)
475                 {
476                         if (!IsStartElement ())
477                                 return false;
478
479                         return (LocalName == localName && NamespaceURI == namespaceName);
480                 }
481
482                 public abstract string LookupNamespace (string prefix);
483
484 #if NET_2_0
485                 public virtual void MoveToAttribute (int i)
486                 {
487                         if (i >= AttributeCount)
488                                 throw new ArgumentOutOfRangeException ();
489                         MoveToFirstAttribute ();
490                         for (int a = 1; a < i; a++)
491                                 MoveToNextAttribute ();
492                 }
493 #else
494                 public abstract void MoveToAttribute (int i);
495 #endif
496
497                 public abstract bool MoveToAttribute (string name);
498
499                 public abstract bool MoveToAttribute (
500                         string localName,
501                         string namespaceName);
502
503                 private bool IsContent (XmlNodeType nodeType)
504                 {
505                         /* MS doc says:
506                          * (non-white space text, CDATA, Element, EndElement, EntityReference, or EndEntity)
507                          */
508                         switch (nodeType) {
509                         case XmlNodeType.Text:
510                                 return true;
511                         case XmlNodeType.CDATA:
512                                 return true;
513                         case XmlNodeType.Element:
514                                 return true;
515                         case XmlNodeType.EndElement:
516                                 return true;
517                         case XmlNodeType.EntityReference:
518                                 return true;
519                         case XmlNodeType.EndEntity:
520                                 return true;
521                         }
522
523                         return false;
524                 }
525
526                 public virtual XmlNodeType MoveToContent ()
527                 {
528                         if (NodeType == XmlNodeType.Attribute)
529                                 MoveToElement ();
530
531                         do {
532                                 if (IsContent (NodeType))
533                                         return NodeType;
534                                 Read ();
535                         } while (!EOF);
536                         return XmlNodeType.None;
537                 }
538
539                 public abstract bool MoveToElement ();
540
541                 public abstract bool MoveToFirstAttribute ();
542
543                 public abstract bool MoveToNextAttribute ();
544
545                 public abstract bool Read ();
546
547                 public abstract bool ReadAttributeValue ();
548
549                 public virtual string ReadElementString ()
550                 {
551                         if (MoveToContent () != XmlNodeType.Element) {
552                                 string error = String.Format ("'{0}' is an invalid node type.",
553                                                               NodeType.ToString ());
554                                 throw XmlError (error);
555                         }
556
557                         string result = String.Empty;
558                         if (!IsEmptyElement) {
559                                 Read ();
560                                 result = ReadString ();
561                                 if (NodeType != XmlNodeType.EndElement) {
562                                         string error = String.Format ("'{0}' is an invalid node type.",
563                                                                       NodeType.ToString ());
564                                         throw XmlError (error);
565                                 }
566                         }
567
568                         Read ();
569                         return result;
570                 }
571
572                 public virtual string ReadElementString (string name)
573                 {
574                         if (MoveToContent () != XmlNodeType.Element) {
575                                 string error = String.Format ("'{0}' is an invalid node type.",
576                                                               NodeType.ToString ());
577                                 throw XmlError (error);
578                         }
579
580                         if (name != Name) {
581                                 string error = String.Format ("The {0} tag from namespace {1} is expected.",
582                                                               Name, NamespaceURI);
583                                 throw XmlError (error);
584                         }
585
586                         string result = String.Empty;
587                         if (!IsEmptyElement) {
588                                 Read ();
589                                 result = ReadString ();
590                                 if (NodeType != XmlNodeType.EndElement) {
591                                         string error = String.Format ("'{0}' is an invalid node type.",
592                                                                       NodeType.ToString ());
593                                         throw XmlError (error);
594                                 }
595                         }
596
597                         Read ();
598                         return result;
599                 }
600
601                 public virtual string ReadElementString (string localName, string namespaceName)
602                 {
603                         if (MoveToContent () != XmlNodeType.Element) {
604                                 string error = String.Format ("'{0}' is an invalid node type.",
605                                                               NodeType.ToString ());
606                                 throw XmlError (error);
607                         }
608
609                         if (localName != LocalName || NamespaceURI != namespaceName) {
610                                 string error = String.Format ("The {0} tag from namespace {1} is expected.",
611                                                               LocalName, NamespaceURI);
612                                 throw XmlError (error);
613                         }
614
615                         string result = String.Empty;
616                         if (!IsEmptyElement) {
617                                 Read ();
618                                 result = ReadString ();
619                                 if (NodeType != XmlNodeType.EndElement) {
620                                         string error = String.Format ("'{0}' is an invalid node type.",
621                                                                       NodeType.ToString ());
622                                         throw XmlError (error);
623                                 }
624                         }
625
626                         Read ();
627                         return result;
628                 }
629
630                 public virtual void ReadEndElement ()
631                 {
632                         if (MoveToContent () != XmlNodeType.EndElement) {
633                                 string error = String.Format ("'{0}' is an invalid node type.",
634                                                               NodeType.ToString ());
635                                 throw XmlError (error);
636                         }
637
638                         Read ();
639                 }
640
641                 public virtual string ReadInnerXml ()
642                 {
643                         if (ReadState != ReadState.Interactive || NodeType == XmlNodeType.EndElement)
644                                 return String.Empty;
645
646                         if (IsEmptyElement) {
647                                 Read ();
648                                 return String.Empty;
649                         }
650                         StringWriter sw = new StringWriter ();
651                         XmlTextWriter xtw = new XmlTextWriter (sw);
652                         if (NodeType == XmlNodeType.Element) {
653                                 int startDepth = Depth;
654                                 Read ();
655                                 while (startDepth < Depth) {
656                                         if (ReadState != ReadState.Interactive)
657                                                 throw XmlError ("Unexpected end of the XML reader.");
658                                         xtw.WriteNode (this, false);
659                                 }
660                                 // reader is now end element, then proceed once more.
661                                 Read ();
662                         }
663                         else
664                                 xtw.WriteNode (this, false);
665
666                         return sw.ToString ();
667                 }
668
669                 public virtual string ReadOuterXml ()
670                 {
671                         if (ReadState != ReadState.Interactive || NodeType == XmlNodeType.EndElement)
672                                 return String.Empty;
673
674                         switch (NodeType) {
675                         case XmlNodeType.Element:
676                         case XmlNodeType.Attribute:
677                                 StringWriter sw = new StringWriter ();
678                                 XmlTextWriter xtw = new XmlTextWriter (sw);
679                                 xtw.WriteNode (this, false);
680                                 return sw.ToString ();
681                         default:
682                                 Skip ();
683                                 return String.Empty;
684                         }
685                 }
686
687                 public virtual void ReadStartElement ()
688                 {
689                         if (MoveToContent () != XmlNodeType.Element) {
690                                 string error = String.Format ("'{0}' is an invalid node type.",
691                                                               NodeType.ToString ());
692                                 throw XmlError (error);
693                         }
694
695                         Read ();
696                 }
697
698                 public virtual void ReadStartElement (string name)
699                 {
700                         if (MoveToContent () != XmlNodeType.Element) {
701                                 string error = String.Format ("'{0}' is an invalid node type.",
702                                                               NodeType.ToString ());
703                                 throw XmlError (error);
704                         }
705
706                         if (name != Name) {
707                                 string error = String.Format ("The {0} tag from namespace {1} is expected.",
708                                                               Name, NamespaceURI);
709                                 throw XmlError (error);
710                         }
711
712                         Read ();
713                 }
714
715                 public virtual void ReadStartElement (string localName, string namespaceName)
716                 {
717                         if (MoveToContent () != XmlNodeType.Element) {
718                                 string error = String.Format ("'{0}' is an invalid node type.",
719                                                               NodeType.ToString ());
720                                 throw XmlError (error);
721                         }
722
723                         if (localName != LocalName || NamespaceURI != namespaceName) {
724                                 string error = String.Format ("Expecting {0} tag from namespace {1}, got {2} and {3} instead",
725                                                               localName, namespaceName,
726                                                               LocalName, NamespaceURI);
727                                 throw XmlError (error);
728                         }
729
730                         Read ();
731                 }
732
733                 public virtual string ReadString ()
734                 {
735                         if (readStringBuffer == null)
736                                 readStringBuffer = new StringBuilder ();
737                         readStringBuffer.Length = 0;
738
739                         MoveToElement ();
740
741                         switch (NodeType) {
742                         default:
743                                 return String.Empty;
744                         case XmlNodeType.Element:
745                                 if (IsEmptyElement)
746                                         return String.Empty;
747                                 do {
748                                         Read ();
749                                         switch (NodeType) {
750                                         case XmlNodeType.Text:
751                                         case XmlNodeType.CDATA:
752                                         case XmlNodeType.Whitespace:
753                                         case XmlNodeType.SignificantWhitespace:
754                                                 readStringBuffer.Append (Value);
755                                                 continue;
756                                         }
757                                         break;
758                                 } while (true);
759                                 break;
760                         case XmlNodeType.Text:
761                         case XmlNodeType.CDATA:
762                         case XmlNodeType.Whitespace:
763                         case XmlNodeType.SignificantWhitespace:
764                                 do {
765                                         switch (NodeType) {
766                                         case XmlNodeType.Text:
767                                         case XmlNodeType.CDATA:
768                                         case XmlNodeType.Whitespace:
769                                         case XmlNodeType.SignificantWhitespace:
770                                                 readStringBuffer.Append (Value);
771                                                 Read ();
772                                                 continue;
773                                         }
774                                         break;
775                                 } while (true);
776                                 break;
777                         }
778                         string ret = readStringBuffer.ToString ();
779                         readStringBuffer.Length = 0;
780                         return ret;
781                 }
782
783 #if NET_2_0
784                 public virtual Type ValueType {
785                         get { return typeof (string); }
786                 }
787
788                 public virtual bool ReadToDescendant (string name)
789                 {
790                         if (ReadState == ReadState.Initial) {
791                                 MoveToContent ();
792                                 if (IsStartElement (name))
793                                         return true;
794                         }
795                         if (NodeType != XmlNodeType.Element || IsEmptyElement)
796                                 return false;
797                         int depth = Depth;
798                         for (Read (); depth < Depth; Read ())
799                                 if (NodeType == XmlNodeType.Element && name == Name)
800                                         return true;
801                         return false;
802                 }
803
804                 public virtual bool ReadToDescendant (string localName, string namespaceURI)
805                 {
806                         if (ReadState == ReadState.Initial) {
807                                 MoveToContent ();
808                                 if (IsStartElement (localName, namespaceURI))
809                                         return true;
810                         }
811                         if (NodeType != XmlNodeType.Element || IsEmptyElement)
812                                 return false;
813                         int depth = Depth;
814                         for (Read (); depth < Depth; Read ())
815                                 if (NodeType == XmlNodeType.Element && localName == LocalName && namespaceURI == NamespaceURI)
816                                         return true;
817                         return false;
818                 }
819
820                 public virtual bool ReadToFollowing (string name)
821                 {
822                         while (Read ())
823                                 if (NodeType == XmlNodeType.Element && name == Name)
824                                         return true;
825                         return false;
826                 }
827
828                 public virtual bool ReadToFollowing (string localName, string namespaceURI)
829                 {
830                         while (Read ())
831                                 if (NodeType == XmlNodeType.Element && localName == Name && namespaceURI == NamespaceURI)
832                                         return true;
833                         return false;
834                 }
835
836                 public virtual bool ReadToNextSibling (string name)
837                 {
838                         if (ReadState != ReadState.Interactive)
839                                 return false;
840                         int depth = Depth;
841                         for (Skip (); depth >= Depth; Skip ())
842                                 if (NodeType == XmlNodeType.Element && name == Name)
843                                         return true;
844                         return false;
845                 }
846
847                 public virtual bool ReadToNextSibling (string localName, string namespaceURI)
848                 {
849                         if (ReadState != ReadState.Interactive)
850                                 return false;
851                         int depth = Depth;
852                         for (Skip (); depth >= Depth; Skip ())
853                                 if (NodeType == XmlNodeType.Element && localName == LocalName && namespaceURI == NamespaceURI)
854                                         return true;
855                         return false;
856                 }
857
858                 public virtual XmlReader ReadSubtree ()
859                 {
860                         return new SubtreeXmlReader (this);
861                 }
862
863                 private string ReadContentString ()
864                 {
865                         if (NodeType == XmlNodeType.Attribute)
866                                 return Value;
867                         return ReadContentString (true);
868                 }
869
870                 private string ReadContentString (bool isText)
871                 {
872                         if (isText) {
873                                 switch (NodeType) {
874                                 case XmlNodeType.Text:
875                                 case XmlNodeType.SignificantWhitespace:
876                                 case XmlNodeType.Whitespace:
877                                 case XmlNodeType.CDATA:
878                                         break;
879                                 default:
880                                         throw new InvalidOperationException (String.Format ("Node type {0} is not supported in this operation.{1}", NodeType, GetLocation ()));
881                                 }
882                         }
883
884                         string value = String.Empty;
885                         do {
886                                 switch (NodeType) {
887                                 case XmlNodeType.Element:
888                                         if (isText)
889                                                 return value;
890                                         throw XmlError ("Child element is not expected in this operation.");
891                                 case XmlNodeType.EndElement:
892                                         return value;
893                                 case XmlNodeType.Text:
894                                 case XmlNodeType.CDATA:
895                                 case XmlNodeType.SignificantWhitespace:
896                                 case XmlNodeType.Whitespace:
897                                         value += Value;
898                                         break;
899                                 }
900                         } while (Read ());
901                         throw XmlError ("Unexpected end of document.");
902                 }
903
904                 string GetLocation ()
905                 {
906                         IXmlLineInfo li = this as IXmlLineInfo;
907                         return li != null && li.HasLineInfo () ?
908                                 String.Format (" {0} (line {1}, column {2})", BaseURI, li.LineNumber, li.LinePosition) : String.Empty;
909                 }
910
911                 [MonoTODO]
912                 public virtual object ReadElementContentAsObject ()
913                 {
914                         return ReadElementContentAs (ValueType, null);
915                 }
916
917                 [MonoTODO]
918                 public virtual object ReadElementContentAsObject (string localName, string namespaceURI)
919                 {
920                         return ReadElementContentAs (ValueType, null, localName, namespaceURI);
921                 }
922
923                 [MonoTODO]
924                 public virtual object ReadContentAsObject ()
925                 {
926                         return ReadContentAs (ValueType, null);
927                 }
928
929                 public virtual object ReadElementContentAs (Type type, IXmlNamespaceResolver resolver)
930                 {
931                         bool isEmpty = IsEmptyElement;
932                         ReadStartElement ();
933                         object obj = ValueAs (isEmpty ? String.Empty : ReadContentString (false), type, resolver);
934                         if (!isEmpty)
935                                 ReadEndElement ();
936                         return obj;
937                 }
938
939                 public virtual object ReadElementContentAs (Type type, IXmlNamespaceResolver resolver, string localName, string namespaceURI)
940                 {
941                         ReadStartElement (localName, namespaceURI);
942                         object obj = ReadContentAs (type, resolver);
943                         ReadEndElement ();
944                         return obj;
945                 }
946
947                 public virtual object ReadContentAs (Type type, IXmlNamespaceResolver resolver)
948                 {
949                         return ValueAs (ReadContentString (), type, resolver);
950                 }
951
952                 private object ValueAs (string text, Type type, IXmlNamespaceResolver resolver)
953                 {
954                         try {
955                                 if (type == typeof (object))
956                                         return text;
957                                 if (type == typeof (XmlQualifiedName)) {
958                                         if (resolver != null)
959                                                 return XmlQualifiedName.Parse (text, resolver);
960                                         else
961                                                 return XmlQualifiedName.Parse (text, this);
962                                 }
963
964                                 switch (Type.GetTypeCode (type)) {
965                                 case TypeCode.Boolean:
966                                         return XQueryConvert.StringToBoolean (text);
967                                 case TypeCode.DateTime:
968                                         return XQueryConvert.StringToDateTime (text);
969                                 case TypeCode.Decimal:
970                                         return XQueryConvert.StringToDecimal (text);
971                                 case TypeCode.Double:
972                                         return XQueryConvert.StringToDouble (text);
973                                 case TypeCode.Int32:
974                                         return XQueryConvert.StringToInt (text);
975                                 case TypeCode.Int64:
976                                         return XQueryConvert.StringToInteger (text);
977                                 case TypeCode.Single:
978                                         return XQueryConvert.StringToFloat (text);
979                                 case TypeCode.String:
980                                         return text;
981                                 }
982                         } catch (Exception ex) {
983                                 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);
984                         }
985                         throw new ArgumentException (String.Format ("Specified type '{0}' is not supported.", type));
986                 }
987
988                 public virtual bool ReadElementContentAsBoolean ()
989                 {
990                         try {
991                                 return XQueryConvert.StringToBoolean (ReadElementContentAsString ());
992                         } catch (FormatException ex) {
993                                 throw XmlError ("Typed value is invalid.", ex);
994                         }
995                 }
996
997                 public virtual DateTime ReadElementContentAsDateTime ()
998                 {
999                         try {
1000                                 return XQueryConvert.StringToDateTime (ReadElementContentAsString ());
1001                         } catch (FormatException ex) {
1002                                 throw XmlError ("Typed value is invalid.", ex);
1003                         }
1004                 }
1005
1006                 public virtual decimal ReadElementContentAsDecimal ()
1007                 {
1008                         try {
1009                                 return XQueryConvert.StringToDecimal (ReadElementContentAsString ());
1010                         } catch (FormatException ex) {
1011                                 throw XmlError ("Typed value is invalid.", ex);
1012                         }
1013                 }
1014
1015                 public virtual double ReadElementContentAsDouble ()
1016                 {
1017                         try {
1018                                 return XQueryConvert.StringToDouble (ReadElementContentAsString ());
1019                         } catch (FormatException ex) {
1020                                 throw XmlError ("Typed value is invalid.", ex);
1021                         }
1022                 }
1023
1024                 public virtual float ReadElementContentAsFloat ()
1025                 {
1026                         try {
1027                                 return XQueryConvert.StringToFloat (ReadElementContentAsString ());
1028                         } catch (FormatException ex) {
1029                                 throw XmlError ("Typed value is invalid.", ex);
1030                         }
1031                 }
1032
1033                 public virtual int ReadElementContentAsInt ()
1034                 {
1035                         try {
1036                                 return XQueryConvert.StringToInt (ReadElementContentAsString ());
1037                         } catch (FormatException ex) {
1038                                 throw XmlError ("Typed value is invalid.", ex);
1039                         }
1040                 }
1041
1042                 public virtual long ReadElementContentAsLong ()
1043                 {
1044                         try {
1045                                 return XQueryConvert.StringToInteger (ReadElementContentAsString ());
1046                         } catch (FormatException ex) {
1047                                 throw XmlError ("Typed value is invalid.", ex);
1048                         }
1049                 }
1050
1051                 public virtual string ReadElementContentAsString ()
1052                 {
1053                         bool isEmpty = IsEmptyElement;
1054                         ReadStartElement ();
1055                         if (isEmpty)
1056                                 return String.Empty;
1057                         string s = ReadContentString (false);
1058                         ReadEndElement ();
1059                         return s;
1060                 }
1061
1062                 public virtual bool ReadElementContentAsBoolean (string localName, string namespaceURI)
1063                 {
1064                         try {
1065                                 return XQueryConvert.StringToBoolean (ReadElementContentAsString (localName, namespaceURI));
1066                         } catch (FormatException ex) {
1067                                 throw XmlError ("Typed value is invalid.", ex);
1068                         }
1069                 }
1070
1071                 public virtual DateTime ReadElementContentAsDateTime (string localName, string namespaceURI)
1072                 {
1073                         try {
1074                                 return XQueryConvert.StringToDateTime (ReadElementContentAsString (localName, namespaceURI));
1075                         } catch (FormatException ex) {
1076                                 throw XmlError ("Typed value is invalid.", ex);
1077                         }
1078                 }
1079
1080                 public virtual decimal ReadElementContentAsDecimal (string localName, string namespaceURI)
1081                 {
1082                         try {
1083                                 return XQueryConvert.StringToDecimal (ReadElementContentAsString (localName, namespaceURI));
1084                         } catch (FormatException ex) {
1085                                 throw XmlError ("Typed value is invalid.", ex);
1086                         }
1087                 }
1088
1089                 public virtual double ReadElementContentAsDouble (string localName, string namespaceURI)
1090                 {
1091                         try {
1092                                 return XQueryConvert.StringToDouble (ReadElementContentAsString (localName, namespaceURI));
1093                         } catch (FormatException ex) {
1094                                 throw XmlError ("Typed value is invalid.", ex);
1095                         }
1096                 }
1097
1098                 public virtual float ReadElementContentAsFloat (string localName, string namespaceURI)
1099                 {
1100                         try {
1101                                 return XQueryConvert.StringToFloat (ReadElementContentAsString (localName, namespaceURI));
1102                         } catch (FormatException ex) {
1103                                 throw XmlError ("Typed value is invalid.", ex);
1104                         }
1105                 }
1106
1107                 public virtual int ReadElementContentAsInt (string localName, string namespaceURI)
1108                 {
1109                         try {
1110                                 return XQueryConvert.StringToInt (ReadElementContentAsString (localName, namespaceURI));
1111                         } catch (FormatException ex) {
1112                                 throw XmlError ("Typed value is invalid.", ex);
1113                         }
1114                 }
1115
1116                 public virtual long ReadElementContentAsLong (string localName, string namespaceURI)
1117                 {
1118                         try {
1119                                 return XQueryConvert.StringToInteger (ReadElementContentAsString (localName, namespaceURI));
1120                         } catch (FormatException ex) {
1121                                 throw XmlError ("Typed value is invalid.", ex);
1122                         }
1123                 }
1124
1125                 public virtual string ReadElementContentAsString (string localName, string namespaceURI)
1126                 {
1127                         ReadStartElement (localName, namespaceURI);
1128                         if (IsEmptyElement)
1129                                 return String.Empty;
1130                         string s = ReadContentString (false);
1131                         ReadEndElement ();
1132                         return s;
1133                 }
1134
1135                 public virtual bool ReadContentAsBoolean ()
1136                 {
1137                         try {
1138                                 return XQueryConvert.StringToBoolean (ReadContentString ());
1139                         } catch (FormatException ex) {
1140                                 throw XmlError ("Typed value is invalid.", ex);
1141                         }
1142                 }
1143
1144                 public virtual DateTime ReadContentAsDateTime ()
1145                 {
1146                         try {
1147                                 return XQueryConvert.StringToDateTime (ReadContentString ());
1148                         } catch (FormatException ex) {
1149                                 throw XmlError ("Typed value is invalid.", ex);
1150                         }
1151                 }
1152
1153                 public virtual decimal ReadContentAsDecimal ()
1154                 {
1155                         try {
1156                                 return XQueryConvert.StringToDecimal (ReadContentString ());
1157                         } catch (FormatException ex) {
1158                                 throw XmlError ("Typed value is invalid.", ex);
1159                         }
1160                 }
1161
1162                 public virtual double ReadContentAsDouble ()
1163                 {
1164                         try {
1165                                 return XQueryConvert.StringToDouble (ReadContentString ());
1166                         } catch (FormatException ex) {
1167                                 throw XmlError ("Typed value is invalid.", ex);
1168                         }
1169                 }
1170
1171                 public virtual float ReadContentAsFloat ()
1172                 {
1173                         try {
1174                                 return XQueryConvert.StringToFloat (ReadContentString ());
1175                         } catch (FormatException ex) {
1176                                 throw XmlError ("Typed value is invalid.", ex);
1177                         }
1178                 }
1179
1180                 public virtual int ReadContentAsInt ()
1181                 {
1182                         try {
1183                                 return XQueryConvert.StringToInt (ReadContentString ());
1184                         } catch (FormatException ex) {
1185                                 throw XmlError ("Typed value is invalid.", ex);
1186                         }
1187                 }
1188
1189                 public virtual long ReadContentAsLong ()
1190                 {
1191                         try {
1192                                 return XQueryConvert.StringToInteger (ReadContentString ());
1193                         } catch (FormatException ex) {
1194                                 throw XmlError ("Typed value is invalid.", ex);
1195                         }
1196                 }
1197
1198                 public virtual string ReadContentAsString ()
1199                 {
1200                         return ReadContentString ();
1201                 }
1202
1203                 public virtual int ReadContentAsBase64 (
1204                         byte [] buffer, int offset, int length)
1205                 {
1206                         CheckSupport ();
1207                         return binary.ReadContentAsBase64 (
1208                                 buffer, offset, length);
1209                 }
1210
1211                 public virtual int ReadContentAsBinHex (
1212                         byte [] buffer, int offset, int length)
1213                 {
1214                         CheckSupport ();
1215                         return binary.ReadContentAsBinHex (
1216                                 buffer, offset, length);
1217                 }
1218
1219                 public virtual int ReadElementContentAsBase64 (
1220                         byte [] buffer, int offset, int length)
1221                 {
1222                         CheckSupport ();
1223                         return binary.ReadElementContentAsBase64 (
1224                                 buffer, offset, length);
1225                 }
1226
1227                 public virtual int ReadElementContentAsBinHex (
1228                         byte [] buffer, int offset, int length)
1229                 {
1230                         CheckSupport ();
1231                         return binary.ReadElementContentAsBinHex (
1232                                 buffer, offset, length);
1233                 }
1234 #endif
1235
1236 #if NET_2_0
1237                 public virtual int ReadValueChunk (
1238                         char [] buffer, int offset, int length)
1239 #else
1240                 internal virtual int ReadValueChunk (
1241                         char [] buffer, int offset, int length)
1242 #endif
1243                 {
1244                         if (!CanReadValueChunk)
1245                                 throw new NotSupportedException ();
1246                         if (binary == null)
1247                                 binary = new XmlReaderBinarySupport (this);
1248                         return binary.ReadValueChunk (buffer, offset, length);
1249                 }
1250
1251                 private void CheckSupport ()
1252                 {
1253                         // Default implementation expects both.
1254                         if (!CanReadBinaryContent || !CanReadValueChunk)
1255                                 throw new NotSupportedException ();
1256                         if (binary == null)
1257                                 binary = new XmlReaderBinarySupport (this);
1258                 }
1259
1260                 public abstract void ResolveEntity ();
1261
1262                 public virtual void Skip ()
1263                 {
1264                         if (ReadState != ReadState.Interactive)
1265                                 return;
1266
1267                         MoveToElement ();
1268                         if (NodeType != XmlNodeType.Element || IsEmptyElement) {
1269                                 Read ();
1270                                 return;
1271                         }
1272                                 
1273                         int depth = Depth;
1274                         while (Read () && depth < Depth)
1275                                 ;
1276                         if (NodeType == XmlNodeType.EndElement)
1277                                 Read ();
1278                 }
1279
1280                 private XmlException XmlError (string message)
1281                 {
1282                         return new XmlException (this as IXmlLineInfo, BaseURI, message);
1283                 }
1284
1285                 private XmlException XmlError (string message, Exception innerException)
1286                 {
1287                         return new XmlException (this as IXmlLineInfo, BaseURI, message);
1288                 }
1289
1290                 #endregion
1291         }
1292 }