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