2007-03-05 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 (false, settings.XmlResolver, url, GetNodeType (settings), context);
314                         XmlReader ret = CreateCustomizedTextReader (xtr, settings);
315                         xtr.CloseInput = true; // forced. See XmlReaderCommonTests.CreateFromUrlClose().
316                         return ret;
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                         reader.EntityHandling = EntityHandling.ExpandEntities;
341
342                         if (settings.ProhibitDtd)
343                                 reader.ProhibitDtd = true;
344
345                         if (!settings.CheckCharacters)
346                                 reader.CharacterChecking = false;
347
348                         // I guess it might be changed in 2.0 RTM to set true
349                         // as default, or just disappear. It goes against
350                         // XmlTextReader's default usage and users will have 
351                         // to close input manually (that's annoying). Moreover,
352                         // MS XmlTextReader consumes text input more than 
353                         // actually read and users can acquire those extra
354                         // consumption by GetRemainder() that returns different
355                         // TextReader.
356                         reader.CloseInput = settings.CloseInput;
357
358                         // I would like to support it in detail later;
359                         // MSDN description looks source of confusion. We don't
360                         // need examples, but precise list of how it works.
361                         reader.Conformance = settings.ConformanceLevel;
362
363                         reader.AdjustLineInfoOffset (settings.LineNumberOffset,
364                                 settings.LinePositionOffset);
365
366                         if (settings.NameTable != null)
367                                 reader.SetNameTable (settings.NameTable);
368
369                         XmlReader r = CreateFilteredXmlReader (reader, settings);
370                         r.settings = settings;
371                         return r;
372                 }
373
374                 private static XmlReader CreateFilteredXmlReader (XmlReader reader, XmlReaderSettings settings)
375                 {
376                         ConformanceLevel conf = ConformanceLevel.Auto;
377                         if (reader is XmlTextReader)
378                                 conf = ((XmlTextReader) reader).Conformance;
379                         else if (reader.Settings != null)
380                                 conf = reader.Settings.ConformanceLevel;
381                         else
382                                 conf = settings.ConformanceLevel;
383                         if (settings.ConformanceLevel != ConformanceLevel.Auto &&
384                                 conf != settings.ConformanceLevel)
385                                 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));
386                         settings.ConformanceLevel = conf;
387
388                         reader = CreateValidatingXmlReader (reader, settings);
389
390                         if (reader.Settings != null &&
391                             (settings.IgnoreComments ||
392                              settings.IgnoreProcessingInstructions ||
393                              settings.IgnoreWhitespace))
394                                 return new XmlFilterReader (reader, settings);
395                         else {
396                                 reader.settings = settings;
397                                 return reader;
398                         }
399                 }
400
401                 private static XmlReader CreateValidatingXmlReader (XmlReader reader, XmlReaderSettings settings)
402                 {
403                         XmlValidatingReader xvr = null;
404                         switch (settings.ValidationType) {
405                         // Auto and XDR are obsoleted in 2.0 and therefore ignored.
406                         default:
407                                 return reader;
408                         case ValidationType.DTD:
409                                 xvr = new XmlValidatingReader (reader);
410                                 xvr.XmlResolver = settings.XmlResolver;
411                                 xvr.ValidationType = ValidationType.DTD;
412                                 break;
413                         case ValidationType.Schema:
414                                 return new XmlSchemaValidatingReader (reader, settings);
415                         }
416
417                         // Actually I don't think they are treated in DTD validation though...
418                         if ((settings.ValidationFlags & XmlSchemaValidationFlags.ProcessIdentityConstraints) == 0)
419                                 throw new NotImplementedException ();
420                         //if ((settings.ValidationFlags & XmlSchemaValidationFlags.ProcessInlineSchema) != 0)
421                         //      throw new NotImplementedException ();
422                         //if ((settings.ValidationFlags & XmlSchemaValidationFlags.ProcessSchemaLocation) != 0)
423                         //      throw new NotImplementedException ();
424                         //if ((settings.ValidationFlags & XmlSchemaValidationFlags.ReportValidationWarnings) == 0)
425                         //      throw new NotImplementedException ();
426
427                         return xvr != null ? xvr : reader;
428                 }
429 #endif
430
431 #if NET_2_0
432                 void IDisposable.Dispose ()
433                 {
434                         Dispose (false);
435                 }
436
437                 protected virtual void Dispose (bool disposing)
438                 {
439                         if (ReadState != ReadState.Closed)
440                                 Close ();
441                 }
442 #endif
443
444                 public abstract string GetAttribute (int i);
445
446                 public abstract string GetAttribute (string name);
447
448                 public abstract string GetAttribute (
449                         string localName,
450                         string namespaceName);
451
452                 public static bool IsName (string s)
453                 {
454                         return s != null && XmlChar.IsName (s);
455                 }
456
457                 public static bool IsNameToken (string s)
458                 {
459                         return s != null && XmlChar.IsNmToken (s);
460                 }
461
462                 public virtual bool IsStartElement ()
463                 {
464                         return (MoveToContent () == XmlNodeType.Element);
465                 }
466
467                 public virtual bool IsStartElement (string name)
468                 {
469                         if (!IsStartElement ())
470                                 return false;
471
472                         return (Name == name);
473                 }
474
475                 public virtual bool IsStartElement (string localName, string namespaceName)
476                 {
477                         if (!IsStartElement ())
478                                 return false;
479
480                         return (LocalName == localName && NamespaceURI == namespaceName);
481                 }
482
483                 public abstract string LookupNamespace (string prefix);
484
485 #if NET_2_0
486                 public virtual void MoveToAttribute (int i)
487                 {
488                         if (i >= AttributeCount)
489                                 throw new ArgumentOutOfRangeException ();
490                         MoveToFirstAttribute ();
491                         for (int a = 0; a < i; a++)
492                                 MoveToNextAttribute ();
493                 }
494 #else
495                 public abstract void MoveToAttribute (int i);
496 #endif
497
498                 public abstract bool MoveToAttribute (string name);
499
500                 public abstract bool MoveToAttribute (
501                         string localName,
502                         string namespaceName);
503
504                 private bool IsContent (XmlNodeType nodeType)
505                 {
506                         /* MS doc says:
507                          * (non-white space text, CDATA, Element, EndElement, EntityReference, or EndEntity)
508                          */
509                         switch (nodeType) {
510                         case XmlNodeType.Text:
511                                 return true;
512                         case XmlNodeType.CDATA:
513                                 return true;
514                         case XmlNodeType.Element:
515                                 return true;
516                         case XmlNodeType.EndElement:
517                                 return true;
518                         case XmlNodeType.EntityReference:
519                                 return true;
520                         case XmlNodeType.EndEntity:
521                                 return true;
522                         }
523
524                         return false;
525                 }
526
527                 public virtual XmlNodeType MoveToContent ()
528                 {
529                         if (NodeType == XmlNodeType.Attribute)
530                                 MoveToElement ();
531
532                         do {
533                                 if (IsContent (NodeType))
534                                         return NodeType;
535                                 Read ();
536                         } while (!EOF);
537                         return XmlNodeType.None;
538                 }
539
540                 public abstract bool MoveToElement ();
541
542                 public abstract bool MoveToFirstAttribute ();
543
544                 public abstract bool MoveToNextAttribute ();
545
546                 public abstract bool Read ();
547
548                 public abstract bool ReadAttributeValue ();
549
550                 public virtual string ReadElementString ()
551                 {
552                         if (MoveToContent () != XmlNodeType.Element) {
553                                 string error = String.Format ("'{0}' is an invalid node type.",
554                                                               NodeType.ToString ());
555                                 throw XmlError (error);
556                         }
557
558                         string result = String.Empty;
559                         if (!IsEmptyElement) {
560                                 Read ();
561                                 result = ReadString ();
562                                 if (NodeType != XmlNodeType.EndElement) {
563                                         string error = String.Format ("'{0}' is an invalid node type.",
564                                                                       NodeType.ToString ());
565                                         throw XmlError (error);
566                                 }
567                         }
568
569                         Read ();
570                         return result;
571                 }
572
573                 public virtual string ReadElementString (string name)
574                 {
575                         if (MoveToContent () != XmlNodeType.Element) {
576                                 string error = String.Format ("'{0}' is an invalid node type.",
577                                                               NodeType.ToString ());
578                                 throw XmlError (error);
579                         }
580
581                         if (name != Name) {
582                                 string error = String.Format ("The {0} tag from namespace {1} is expected.",
583                                                               Name, NamespaceURI);
584                                 throw XmlError (error);
585                         }
586
587                         string result = String.Empty;
588                         if (!IsEmptyElement) {
589                                 Read ();
590                                 result = ReadString ();
591                                 if (NodeType != XmlNodeType.EndElement) {
592                                         string error = String.Format ("'{0}' is an invalid node type.",
593                                                                       NodeType.ToString ());
594                                         throw XmlError (error);
595                                 }
596                         }
597
598                         Read ();
599                         return result;
600                 }
601
602                 public virtual string ReadElementString (string localName, string namespaceName)
603                 {
604                         if (MoveToContent () != XmlNodeType.Element) {
605                                 string error = String.Format ("'{0}' is an invalid node type.",
606                                                               NodeType.ToString ());
607                                 throw XmlError (error);
608                         }
609
610                         if (localName != LocalName || NamespaceURI != namespaceName) {
611                                 string error = String.Format ("The {0} tag from namespace {1} is expected.",
612                                                               LocalName, NamespaceURI);
613                                 throw XmlError (error);
614                         }
615
616                         string result = String.Empty;
617                         if (!IsEmptyElement) {
618                                 Read ();
619                                 result = ReadString ();
620                                 if (NodeType != XmlNodeType.EndElement) {
621                                         string error = String.Format ("'{0}' is an invalid node type.",
622                                                                       NodeType.ToString ());
623                                         throw XmlError (error);
624                                 }
625                         }
626
627                         Read ();
628                         return result;
629                 }
630
631                 public virtual void ReadEndElement ()
632                 {
633                         if (MoveToContent () != XmlNodeType.EndElement) {
634                                 string error = String.Format ("'{0}' is an invalid node type.",
635                                                               NodeType.ToString ());
636                                 throw XmlError (error);
637                         }
638
639                         Read ();
640                 }
641
642                 public virtual string ReadInnerXml ()
643                 {
644                         if (ReadState != ReadState.Interactive || NodeType == XmlNodeType.EndElement)
645                                 return String.Empty;
646
647                         if (IsEmptyElement) {
648                                 Read ();
649                                 return String.Empty;
650                         }
651                         StringWriter sw = new StringWriter ();
652                         XmlTextWriter xtw = new XmlTextWriter (sw);
653                         if (NodeType == XmlNodeType.Element) {
654                                 int startDepth = Depth;
655                                 Read ();
656                                 while (startDepth < Depth) {
657                                         if (ReadState != ReadState.Interactive)
658                                                 throw XmlError ("Unexpected end of the XML reader.");
659                                         xtw.WriteNode (this, false);
660                                 }
661                                 // reader is now end element, then proceed once more.
662                                 Read ();
663                         }
664                         else
665                                 xtw.WriteNode (this, false);
666
667                         return sw.ToString ();
668                 }
669
670                 public virtual string ReadOuterXml ()
671                 {
672                         if (ReadState != ReadState.Interactive || NodeType == XmlNodeType.EndElement)
673                                 return String.Empty;
674
675                         switch (NodeType) {
676                         case XmlNodeType.Element:
677                         case XmlNodeType.Attribute:
678                                 StringWriter sw = new StringWriter ();
679                                 XmlTextWriter xtw = new XmlTextWriter (sw);
680                                 xtw.WriteNode (this, false);
681                                 return sw.ToString ();
682                         default:
683                                 Skip ();
684                                 return String.Empty;
685                         }
686                 }
687
688                 public virtual void ReadStartElement ()
689                 {
690                         if (MoveToContent () != XmlNodeType.Element) {
691                                 string error = String.Format ("'{0}' is an invalid node type.",
692                                                               NodeType.ToString ());
693                                 throw XmlError (error);
694                         }
695
696                         Read ();
697                 }
698
699                 public virtual void ReadStartElement (string name)
700                 {
701                         if (MoveToContent () != XmlNodeType.Element) {
702                                 string error = String.Format ("'{0}' is an invalid node type.",
703                                                               NodeType.ToString ());
704                                 throw XmlError (error);
705                         }
706
707                         if (name != Name) {
708                                 string error = String.Format ("The {0} tag from namespace {1} is expected.",
709                                                               Name, NamespaceURI);
710                                 throw XmlError (error);
711                         }
712
713                         Read ();
714                 }
715
716                 public virtual void ReadStartElement (string localName, string namespaceName)
717                 {
718                         if (MoveToContent () != XmlNodeType.Element) {
719                                 string error = String.Format ("'{0}' is an invalid node type.",
720                                                               NodeType.ToString ());
721                                 throw XmlError (error);
722                         }
723
724                         if (localName != LocalName || NamespaceURI != namespaceName) {
725                                 string error = String.Format ("Expecting {0} tag from namespace {1}, got {2} and {3} instead",
726                                                               localName, namespaceName,
727                                                               LocalName, NamespaceURI);
728                                 throw XmlError (error);
729                         }
730
731                         Read ();
732                 }
733
734                 public virtual string ReadString ()
735                 {
736                         if (readStringBuffer == null)
737                                 readStringBuffer = new StringBuilder ();
738                         readStringBuffer.Length = 0;
739
740                         MoveToElement ();
741
742                         switch (NodeType) {
743                         default:
744                                 return String.Empty;
745                         case XmlNodeType.Element:
746                                 if (IsEmptyElement)
747                                         return String.Empty;
748                                 do {
749                                         Read ();
750                                         switch (NodeType) {
751                                         case XmlNodeType.Text:
752                                         case XmlNodeType.CDATA:
753                                         case XmlNodeType.Whitespace:
754                                         case XmlNodeType.SignificantWhitespace:
755                                                 readStringBuffer.Append (Value);
756                                                 continue;
757                                         }
758                                         break;
759                                 } while (true);
760                                 break;
761                         case XmlNodeType.Text:
762                         case XmlNodeType.CDATA:
763                         case XmlNodeType.Whitespace:
764                         case XmlNodeType.SignificantWhitespace:
765                                 do {
766                                         switch (NodeType) {
767                                         case XmlNodeType.Text:
768                                         case XmlNodeType.CDATA:
769                                         case XmlNodeType.Whitespace:
770                                         case XmlNodeType.SignificantWhitespace:
771                                                 readStringBuffer.Append (Value);
772                                                 Read ();
773                                                 continue;
774                                         }
775                                         break;
776                                 } while (true);
777                                 break;
778                         }
779                         string ret = readStringBuffer.ToString ();
780                         readStringBuffer.Length = 0;
781                         return ret;
782                 }
783
784 #if NET_2_0
785                 public virtual Type ValueType {
786                         get { return typeof (string); }
787                 }
788
789                 public virtual bool ReadToDescendant (string name)
790                 {
791                         if (ReadState == ReadState.Initial) {
792                                 MoveToContent ();
793                                 if (IsStartElement (name))
794                                         return true;
795                         }
796                         if (NodeType != XmlNodeType.Element || IsEmptyElement)
797                                 return false;
798                         int depth = Depth;
799                         for (Read (); depth < Depth; Read ())
800                                 if (NodeType == XmlNodeType.Element && name == Name)
801                                         return true;
802                         return false;
803                 }
804
805                 public virtual bool ReadToDescendant (string localName, string namespaceURI)
806                 {
807                         if (ReadState == ReadState.Initial) {
808                                 MoveToContent ();
809                                 if (IsStartElement (localName, namespaceURI))
810                                         return true;
811                         }
812                         if (NodeType != XmlNodeType.Element || IsEmptyElement)
813                                 return false;
814                         int depth = Depth;
815                         for (Read (); depth < Depth; Read ())
816                                 if (NodeType == XmlNodeType.Element && localName == LocalName && namespaceURI == NamespaceURI)
817                                         return true;
818                         return false;
819                 }
820
821                 public virtual bool ReadToFollowing (string name)
822                 {
823                         while (Read ())
824                                 if (NodeType == XmlNodeType.Element && name == Name)
825                                         return true;
826                         return false;
827                 }
828
829                 public virtual bool ReadToFollowing (string localName, string namespaceURI)
830                 {
831                         while (Read ())
832                                 if (NodeType == XmlNodeType.Element && localName == Name && namespaceURI == NamespaceURI)
833                                         return true;
834                         return false;
835                 }
836
837                 public virtual bool ReadToNextSibling (string name)
838                 {
839                         if (ReadState != ReadState.Interactive)
840                                 return false;
841                         int depth = Depth;
842                         for (Skip (); depth >= Depth; Skip ())
843                                 if (NodeType == XmlNodeType.Element && name == Name)
844                                         return true;
845                         return false;
846                 }
847
848                 public virtual bool ReadToNextSibling (string localName, string namespaceURI)
849                 {
850                         if (ReadState != ReadState.Interactive)
851                                 return false;
852                         int depth = Depth;
853                         for (Skip (); depth >= Depth; Skip ())
854                                 if (NodeType == XmlNodeType.Element && localName == LocalName && namespaceURI == NamespaceURI)
855                                         return true;
856                         return false;
857                 }
858
859                 public virtual XmlReader ReadSubtree ()
860                 {
861                         return new SubtreeXmlReader (this);
862                 }
863
864                 private string ReadContentString ()
865                 {
866                         if (NodeType == XmlNodeType.Attribute)
867                                 return Value;
868                         return ReadContentString (true);
869                 }
870
871                 private string ReadContentString (bool isText)
872                 {
873                         if (isText) {
874                                 switch (NodeType) {
875                                 case XmlNodeType.Text:
876                                 case XmlNodeType.SignificantWhitespace:
877                                 case XmlNodeType.Whitespace:
878                                 case XmlNodeType.CDATA:
879                                         break;
880                                 default:
881                                         throw new InvalidOperationException (String.Format ("Node type {0} is not supported in this operation.{1}", NodeType, GetLocation ()));
882                                 }
883                         }
884
885                         string value = String.Empty;
886                         do {
887                                 switch (NodeType) {
888                                 case XmlNodeType.Element:
889                                         if (isText)
890                                                 return value;
891                                         throw XmlError ("Child element is not expected in this operation.");
892                                 case XmlNodeType.EndElement:
893                                         return value;
894                                 case XmlNodeType.Text:
895                                 case XmlNodeType.CDATA:
896                                 case XmlNodeType.SignificantWhitespace:
897                                 case XmlNodeType.Whitespace:
898                                         value += Value;
899                                         break;
900                                 }
901                         } while (Read ());
902                         throw XmlError ("Unexpected end of document.");
903                 }
904
905                 string GetLocation ()
906                 {
907                         IXmlLineInfo li = this as IXmlLineInfo;
908                         return li != null && li.HasLineInfo () ?
909                                 String.Format (" {0} (line {1}, column {2})", BaseURI, li.LineNumber, li.LinePosition) : String.Empty;
910                 }
911
912                 [MonoTODO]
913                 public virtual object ReadElementContentAsObject ()
914                 {
915                         return ReadElementContentAs (ValueType, null);
916                 }
917
918                 [MonoTODO]
919                 public virtual object ReadElementContentAsObject (string localName, string namespaceURI)
920                 {
921                         return ReadElementContentAs (ValueType, null, localName, namespaceURI);
922                 }
923
924                 [MonoTODO]
925                 public virtual object ReadContentAsObject ()
926                 {
927                         return ReadContentAs (ValueType, null);
928                 }
929
930                 public virtual object ReadElementContentAs (Type type, IXmlNamespaceResolver resolver)
931                 {
932                         bool isEmpty = IsEmptyElement;
933                         ReadStartElement ();
934                         object obj = ValueAs (isEmpty ? String.Empty : ReadContentString (false), type, resolver);
935                         if (!isEmpty)
936                                 ReadEndElement ();
937                         return obj;
938                 }
939
940                 public virtual object ReadElementContentAs (Type type, IXmlNamespaceResolver resolver, string localName, string namespaceURI)
941                 {
942                         ReadStartElement (localName, namespaceURI);
943                         object obj = ReadContentAs (type, resolver);
944                         ReadEndElement ();
945                         return obj;
946                 }
947
948                 public virtual object ReadContentAs (Type type, IXmlNamespaceResolver resolver)
949                 {
950                         return ValueAs (ReadContentString (), type, resolver);
951                 }
952
953                 private object ValueAs (string text, Type type, IXmlNamespaceResolver resolver)
954                 {
955                         try {
956                                 if (type == typeof (object))
957                                         return text;
958                                 if (type == typeof (XmlQualifiedName)) {
959                                         if (resolver != null)
960                                                 return XmlQualifiedName.Parse (text, resolver);
961                                         else
962                                                 return XmlQualifiedName.Parse (text, this);
963                                 }
964
965                                 switch (Type.GetTypeCode (type)) {
966                                 case TypeCode.Boolean:
967                                         return XQueryConvert.StringToBoolean (text);
968                                 case TypeCode.DateTime:
969                                         return XQueryConvert.StringToDateTime (text);
970                                 case TypeCode.Decimal:
971                                         return XQueryConvert.StringToDecimal (text);
972                                 case TypeCode.Double:
973                                         return XQueryConvert.StringToDouble (text);
974                                 case TypeCode.Int32:
975                                         return XQueryConvert.StringToInt (text);
976                                 case TypeCode.Int64:
977                                         return XQueryConvert.StringToInteger (text);
978                                 case TypeCode.Single:
979                                         return XQueryConvert.StringToFloat (text);
980                                 case TypeCode.String:
981                                         return text;
982                                 }
983                         } catch (Exception ex) {
984                                 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);
985                         }
986                         throw new ArgumentException (String.Format ("Specified type '{0}' is not supported.", type));
987                 }
988
989                 public virtual bool ReadElementContentAsBoolean ()
990                 {
991                         try {
992                                 return XQueryConvert.StringToBoolean (ReadElementContentAsString ());
993                         } catch (FormatException ex) {
994                                 throw XmlError ("Typed value is invalid.", ex);
995                         }
996                 }
997
998                 public virtual DateTime ReadElementContentAsDateTime ()
999                 {
1000                         try {
1001                                 return XQueryConvert.StringToDateTime (ReadElementContentAsString ());
1002                         } catch (FormatException ex) {
1003                                 throw XmlError ("Typed value is invalid.", ex);
1004                         }
1005                 }
1006
1007                 public virtual decimal ReadElementContentAsDecimal ()
1008                 {
1009                         try {
1010                                 return XQueryConvert.StringToDecimal (ReadElementContentAsString ());
1011                         } catch (FormatException ex) {
1012                                 throw XmlError ("Typed value is invalid.", ex);
1013                         }
1014                 }
1015
1016                 public virtual double ReadElementContentAsDouble ()
1017                 {
1018                         try {
1019                                 return XQueryConvert.StringToDouble (ReadElementContentAsString ());
1020                         } catch (FormatException ex) {
1021                                 throw XmlError ("Typed value is invalid.", ex);
1022                         }
1023                 }
1024
1025                 public virtual float ReadElementContentAsFloat ()
1026                 {
1027                         try {
1028                                 return XQueryConvert.StringToFloat (ReadElementContentAsString ());
1029                         } catch (FormatException ex) {
1030                                 throw XmlError ("Typed value is invalid.", ex);
1031                         }
1032                 }
1033
1034                 public virtual int ReadElementContentAsInt ()
1035                 {
1036                         try {
1037                                 return XQueryConvert.StringToInt (ReadElementContentAsString ());
1038                         } catch (FormatException ex) {
1039                                 throw XmlError ("Typed value is invalid.", ex);
1040                         }
1041                 }
1042
1043                 public virtual long ReadElementContentAsLong ()
1044                 {
1045                         try {
1046                                 return XQueryConvert.StringToInteger (ReadElementContentAsString ());
1047                         } catch (FormatException ex) {
1048                                 throw XmlError ("Typed value is invalid.", ex);
1049                         }
1050                 }
1051
1052                 public virtual string ReadElementContentAsString ()
1053                 {
1054                         bool isEmpty = IsEmptyElement;
1055                         ReadStartElement ();
1056                         if (isEmpty)
1057                                 return String.Empty;
1058                         string s = ReadContentString (false);
1059                         ReadEndElement ();
1060                         return s;
1061                 }
1062
1063                 public virtual bool ReadElementContentAsBoolean (string localName, string namespaceURI)
1064                 {
1065                         try {
1066                                 return XQueryConvert.StringToBoolean (ReadElementContentAsString (localName, namespaceURI));
1067                         } catch (FormatException ex) {
1068                                 throw XmlError ("Typed value is invalid.", ex);
1069                         }
1070                 }
1071
1072                 public virtual DateTime ReadElementContentAsDateTime (string localName, string namespaceURI)
1073                 {
1074                         try {
1075                                 return XQueryConvert.StringToDateTime (ReadElementContentAsString (localName, namespaceURI));
1076                         } catch (FormatException ex) {
1077                                 throw XmlError ("Typed value is invalid.", ex);
1078                         }
1079                 }
1080
1081                 public virtual decimal ReadElementContentAsDecimal (string localName, string namespaceURI)
1082                 {
1083                         try {
1084                                 return XQueryConvert.StringToDecimal (ReadElementContentAsString (localName, namespaceURI));
1085                         } catch (FormatException ex) {
1086                                 throw XmlError ("Typed value is invalid.", ex);
1087                         }
1088                 }
1089
1090                 public virtual double ReadElementContentAsDouble (string localName, string namespaceURI)
1091                 {
1092                         try {
1093                                 return XQueryConvert.StringToDouble (ReadElementContentAsString (localName, namespaceURI));
1094                         } catch (FormatException ex) {
1095                                 throw XmlError ("Typed value is invalid.", ex);
1096                         }
1097                 }
1098
1099                 public virtual float ReadElementContentAsFloat (string localName, string namespaceURI)
1100                 {
1101                         try {
1102                                 return XQueryConvert.StringToFloat (ReadElementContentAsString (localName, namespaceURI));
1103                         } catch (FormatException ex) {
1104                                 throw XmlError ("Typed value is invalid.", ex);
1105                         }
1106                 }
1107
1108                 public virtual int ReadElementContentAsInt (string localName, string namespaceURI)
1109                 {
1110                         try {
1111                                 return XQueryConvert.StringToInt (ReadElementContentAsString (localName, namespaceURI));
1112                         } catch (FormatException ex) {
1113                                 throw XmlError ("Typed value is invalid.", ex);
1114                         }
1115                 }
1116
1117                 public virtual long ReadElementContentAsLong (string localName, string namespaceURI)
1118                 {
1119                         try {
1120                                 return XQueryConvert.StringToInteger (ReadElementContentAsString (localName, namespaceURI));
1121                         } catch (FormatException ex) {
1122                                 throw XmlError ("Typed value is invalid.", ex);
1123                         }
1124                 }
1125
1126                 public virtual string ReadElementContentAsString (string localName, string namespaceURI)
1127                 {
1128                         bool isEmpty = IsEmptyElement;
1129                         ReadStartElement (localName, namespaceURI);
1130                         if (isEmpty)
1131                                 return String.Empty;
1132                         string s = ReadContentString (false);
1133                         ReadEndElement ();
1134                         return s;
1135                 }
1136
1137                 public virtual bool ReadContentAsBoolean ()
1138                 {
1139                         try {
1140                                 return XQueryConvert.StringToBoolean (ReadContentString ());
1141                         } catch (FormatException ex) {
1142                                 throw XmlError ("Typed value is invalid.", ex);
1143                         }
1144                 }
1145
1146                 public virtual DateTime ReadContentAsDateTime ()
1147                 {
1148                         try {
1149                                 return XQueryConvert.StringToDateTime (ReadContentString ());
1150                         } catch (FormatException ex) {
1151                                 throw XmlError ("Typed value is invalid.", ex);
1152                         }
1153                 }
1154
1155                 public virtual decimal ReadContentAsDecimal ()
1156                 {
1157                         try {
1158                                 return XQueryConvert.StringToDecimal (ReadContentString ());
1159                         } catch (FormatException ex) {
1160                                 throw XmlError ("Typed value is invalid.", ex);
1161                         }
1162                 }
1163
1164                 public virtual double ReadContentAsDouble ()
1165                 {
1166                         try {
1167                                 return XQueryConvert.StringToDouble (ReadContentString ());
1168                         } catch (FormatException ex) {
1169                                 throw XmlError ("Typed value is invalid.", ex);
1170                         }
1171                 }
1172
1173                 public virtual float ReadContentAsFloat ()
1174                 {
1175                         try {
1176                                 return XQueryConvert.StringToFloat (ReadContentString ());
1177                         } catch (FormatException ex) {
1178                                 throw XmlError ("Typed value is invalid.", ex);
1179                         }
1180                 }
1181
1182                 public virtual int ReadContentAsInt ()
1183                 {
1184                         try {
1185                                 return XQueryConvert.StringToInt (ReadContentString ());
1186                         } catch (FormatException ex) {
1187                                 throw XmlError ("Typed value is invalid.", ex);
1188                         }
1189                 }
1190
1191                 public virtual long ReadContentAsLong ()
1192                 {
1193                         try {
1194                                 return XQueryConvert.StringToInteger (ReadContentString ());
1195                         } catch (FormatException ex) {
1196                                 throw XmlError ("Typed value is invalid.", ex);
1197                         }
1198                 }
1199
1200                 public virtual string ReadContentAsString ()
1201                 {
1202                         return ReadContentString ();
1203                 }
1204
1205                 public virtual int ReadContentAsBase64 (
1206                         byte [] buffer, int offset, int length)
1207                 {
1208                         CheckSupport ();
1209                         return binary.ReadContentAsBase64 (
1210                                 buffer, offset, length);
1211                 }
1212
1213                 public virtual int ReadContentAsBinHex (
1214                         byte [] buffer, int offset, int length)
1215                 {
1216                         CheckSupport ();
1217                         return binary.ReadContentAsBinHex (
1218                                 buffer, offset, length);
1219                 }
1220
1221                 public virtual int ReadElementContentAsBase64 (
1222                         byte [] buffer, int offset, int length)
1223                 {
1224                         CheckSupport ();
1225                         return binary.ReadElementContentAsBase64 (
1226                                 buffer, offset, length);
1227                 }
1228
1229                 public virtual int ReadElementContentAsBinHex (
1230                         byte [] buffer, int offset, int length)
1231                 {
1232                         CheckSupport ();
1233                         return binary.ReadElementContentAsBinHex (
1234                                 buffer, offset, length);
1235                 }
1236 #endif
1237
1238 #if NET_2_0
1239                 public virtual int ReadValueChunk (
1240                         char [] buffer, int offset, int length)
1241 #else
1242                 internal virtual int ReadValueChunk (
1243                         char [] buffer, int offset, int length)
1244 #endif
1245                 {
1246                         if (!CanReadValueChunk)
1247                                 throw new NotSupportedException ();
1248                         if (binary == null)
1249                                 binary = new XmlReaderBinarySupport (this);
1250                         return binary.ReadValueChunk (buffer, offset, length);
1251                 }
1252
1253                 private void CheckSupport ()
1254                 {
1255                         // Default implementation expects both.
1256                         if (!CanReadBinaryContent || !CanReadValueChunk)
1257                                 throw new NotSupportedException ();
1258                         if (binary == null)
1259                                 binary = new XmlReaderBinarySupport (this);
1260                 }
1261
1262                 public abstract void ResolveEntity ();
1263
1264                 public virtual void Skip ()
1265                 {
1266                         if (ReadState != ReadState.Interactive)
1267                                 return;
1268
1269                         MoveToElement ();
1270                         if (NodeType != XmlNodeType.Element || IsEmptyElement) {
1271                                 Read ();
1272                                 return;
1273                         }
1274                                 
1275                         int depth = Depth;
1276                         while (Read () && depth < Depth)
1277                                 ;
1278                         if (NodeType == XmlNodeType.EndElement)
1279                                 Read ();
1280                 }
1281
1282                 private XmlException XmlError (string message)
1283                 {
1284                         return new XmlException (this as IXmlLineInfo, BaseURI, message);
1285                 }
1286
1287                 private XmlException XmlError (string message, Exception innerException)
1288                 {
1289                         return new XmlException (this as IXmlLineInfo, BaseURI, message);
1290                 }
1291
1292                 #endregion
1293         }
1294 }