2003-08-07 Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
[mono.git] / mcs / class / System.XML / System.Xml / XmlNodeReader.cs
1 //
2 // System.Xml.XmlNodeReader.cs
3 //
4 // Author:
5 //      Duncan Mak  (duncan@ximian.com)
6 //      Atsushi Enomoto  (ginga@kit.hi-ho.ne.jp)
7 //
8 // (C) Ximian, Inc.
9 // (C) Atsushi Enomoto
10 //
11
12 using System;
13 using System.Collections;
14 using System.Xml;
15 using System.Text;
16
17 namespace System.Xml
18 {
19         public class XmlNodeReader : XmlReader
20         {
21                 XmlDocument document;
22                 XmlNode startNode;
23                 XmlNode current;
24                 ReadState state = ReadState.Initial;
25                 int depth;
26                 bool isEndElement;
27                 bool nextIsEndElement;  // used for ReadString()
28                 bool alreadyRead;
29                 StringBuilder valueBuilder = new StringBuilder ();
30                 XmlNamespaceManager defaultNsmgr;
31                 Stack entityReaderStack = new Stack ();
32                 XmlTextReader entityReader;
33
34                 private XmlNode ownerElement {
35                         get {
36                                 if (current.ParentNode != null && current.ParentNode.NodeType == XmlNodeType.Attribute)
37                                         return ((XmlAttribute) current.ParentNode).OwnerElement;
38                                 return (current.NodeType == XmlNodeType.Attribute) ? ((XmlAttribute)current).OwnerElement : current;
39                         }
40                 }
41
42                 #region Constructor
43
44                 public XmlNodeReader (XmlNode node)
45                 {
46                         startNode = node;
47                         document = startNode.NodeType == XmlNodeType.Document ?
48                                 startNode as XmlDocument : startNode.OwnerDocument;
49
50                         if (node.NodeType != XmlNodeType.Document
51                                 && node.NodeType != XmlNodeType.DocumentFragment)
52                                 alreadyRead = true;
53                         defaultNsmgr = new XmlNamespaceManager (this.NameTable);
54
55                 }
56                 
57                 #endregion
58
59                 #region Properties
60
61                 public override int AttributeCount {
62                         get {
63                                 if (entityReader != null)
64                                         return entityReader.ReadState == ReadState.Interactive ?
65                                                 entityReader.AttributeCount : 0;
66
67                                 if (isEndElement || current == null || current.Attributes == null)
68                                         return 0;
69                                 return ownerElement.Attributes.Count;
70                         }
71                 }
72
73                 public override string BaseURI {
74                         get {
75                                 if (entityReader != null && entityReader.ReadState != ReadState.Initial)
76                                         return entityReader.BaseURI;
77
78                                 if (current == null)
79                                         return String.Empty;
80                                 return current.BaseURI;
81                         }
82                 }
83
84                 public override bool CanResolveEntity {
85                         get {
86                                 return true;
87                         }
88                 }
89
90                 public override int Depth {
91                         get {
92                                 if (entityReader != null && entityReader.ReadState == ReadState.Interactive)
93                                         return entityReader.Depth + depth + entityReaderStack.Count + 1;
94
95                                 return depth;
96                         }
97                 }
98
99                 public override bool EOF {
100                         get {
101                                 return this.ReadState == ReadState.EndOfFile 
102                                 || this.ReadState == ReadState.Error;
103                         }
104                 }
105
106                 public override bool HasAttributes {
107                         get {
108                                 if (entityReader != null)
109                                         return entityReader.ReadState == ReadState.Interactive ?
110                                               entityReader.HasAttributes : false;
111
112                                 if (isEndElement || current == null)
113                                         return false;
114
115                                 if (current.Attributes == null ||
116                                         current.Attributes.Count == 0)
117                                         return false;
118                                 else
119                                         return true;
120                         }
121                 }
122
123                 public override bool HasValue {
124                         get {
125                                 if (entityReader != null)
126                                         return entityReader.ReadState == ReadState.Interactive ?
127                                                 entityReader.IsDefault : false;
128
129                                 if (current == null)
130                                         return false;
131
132                                 if (current.NodeType == XmlNodeType.Element ||
133                                     current.NodeType == XmlNodeType.EntityReference ||
134                                     current.NodeType == XmlNodeType.Document ||
135                                     current.NodeType == XmlNodeType.DocumentFragment ||
136                                     current.NodeType == XmlNodeType.Notation ||
137                                     current.NodeType == XmlNodeType.EndElement ||
138                                     current.NodeType == XmlNodeType.EndEntity)
139                                         return false;
140                                 else
141                                         return true;
142                         }
143                               
144                 }
145
146                 public override bool IsDefault {
147                         get {
148                                 if (entityReader != null)
149                                         return entityReader.ReadState == ReadState.Interactive ?
150                                                 entityReader.IsDefault : false;
151
152                                 if (current == null)
153                                         return false;
154
155                                 if (current.NodeType != XmlNodeType.Attribute)
156                                         return false;
157                                 else
158                                 {
159                                         return ((XmlAttribute) current).isDefault;
160                                 }
161                         }
162                 }
163
164                 public override bool IsEmptyElement {
165                         get {
166                                 if (entityReader != null)
167                                         return entityReader.ReadState == ReadState.Interactive ?
168                                                 entityReader.IsDefault : false;
169
170                                 if (current == null)
171                                         return false;
172
173                                 if(current.NodeType == XmlNodeType.Element)
174                                         return ((XmlElement) current).IsEmpty;
175                                 else 
176                                         return false;
177                         }
178                 }
179
180                 public override string this [int i] {
181                         get { return GetAttribute (i); }
182                 }
183
184                 public override string this [string name] {
185                         get { return GetAttribute (name); }
186                 }
187
188                 public override string this [string name, string namespaceURI] {
189                         get { return GetAttribute (name, namespaceURI); }
190                 }
191
192                 public override string LocalName {
193                         get {
194                                 if (entityReader != null && entityReader.ReadState != ReadState.Initial)
195                                         return entityReader.LocalName;
196
197                                 if (current == null)
198                                         return String.Empty;
199
200                                 switch (current.NodeType) {
201                                 case XmlNodeType.Attribute:
202                                 case XmlNodeType.DocumentType:
203                                 case XmlNodeType.Element:
204                                 case XmlNodeType.EntityReference:
205                                 case XmlNodeType.ProcessingInstruction:
206                                 case XmlNodeType.XmlDeclaration:
207                                         return current.LocalName;
208                                 }
209
210                                 return String.Empty;
211                         }
212                 }
213
214                 public override string Name {
215                         get {
216                                 if (entityReader != null && entityReader.ReadState != ReadState.Initial)
217                                         return entityReader.Name;
218
219                                 if (current == null)
220                                         return String.Empty;
221
222                                 switch (current.NodeType) {
223                                 case XmlNodeType.Attribute:
224                                 case XmlNodeType.DocumentType:
225                                 case XmlNodeType.Element:
226                                 case XmlNodeType.EntityReference:
227                                 case XmlNodeType.ProcessingInstruction:
228                                 case XmlNodeType.XmlDeclaration:
229                                         return current.Name;
230                                 }
231
232                                 return String.Empty;
233                         }
234                 }
235
236                 public override string NamespaceURI {
237                         get {
238                                 if (entityReader != null && entityReader.ReadState != ReadState.Initial)
239                                         return entityReader.NamespaceURI;
240
241                                 if (current == null)
242                                         return String.Empty;
243
244                                 return current.NamespaceURI;
245                         }
246                 }
247
248                 public override XmlNameTable NameTable {
249                         get { return document.NameTable; }
250                 }
251
252                 public override XmlNodeType NodeType {
253                         get {
254                                 if (entityReader != null)
255                                         switch (entityReader.ReadState) {
256                                         case ReadState.Interactive:
257                                                 return entityReader.NodeType;
258                                         case ReadState.Initial:
259                                                 return XmlNodeType.EntityReference;
260                                         case ReadState.EndOfFile:
261                                                 return XmlNodeType.EndEntity;
262                                         }
263
264                                 if (current == null)
265                                         return XmlNodeType.None;
266
267                                 return isEndElement ? XmlNodeType.EndElement : current.NodeType;
268                         }
269                 }
270
271                 public override string Prefix {
272                         get { 
273                                 if (entityReader != null && entityReader.ReadState != ReadState.Initial)
274                                         return entityReader.Prefix;
275
276                                 if (current == null)
277                                         return String.Empty;
278
279                                 return current.Prefix;
280                         }
281                 }
282
283                 public override char QuoteChar {
284                         get {
285                                 if (entityReader != null && entityReader.ReadState != ReadState.Initial)
286                                         return entityReader.QuoteChar;
287
288                                 return '"';
289                         }
290                 }
291
292                 public override ReadState ReadState {
293                         get { return state; }
294                 }
295
296                 public override string Value {
297                         get {
298                                 if (entityReader != null && entityReader.ReadState != ReadState.Initial)
299                                         return entityReader.Value;
300
301                                 if (NodeType == XmlNodeType.DocumentType)
302                                         return ((XmlDocumentType) current).InternalSubset;
303                                 else
304                                         return HasValue ? current.Value : String.Empty;
305                         }
306                 }
307
308                 public override string XmlLang {
309                         get {
310                                 if (entityReader != null && entityReader.ReadState != ReadState.Initial)
311                                         return entityReader.XmlLang;
312
313                                 if (current == null)
314                                         return String.Empty;
315
316                                 return current.XmlLang;
317                         }
318                 }
319
320                 public override XmlSpace XmlSpace {
321                         get {
322                                 if (entityReader != null && entityReader.ReadState != ReadState.Initial)
323                                         return entityReader.XmlSpace;
324
325                                 if (current == null)
326                                         return XmlSpace.None;
327
328                                 return current.XmlSpace;
329                         }
330                 }
331                 #endregion
332
333                 #region Methods
334
335                 // If current entityReference is a child of an attribute,
336                 // then MoveToAttribute simply means that we no more need this entity reader.
337                 // Otherwise, this invokation means that
338                 // it is expected to move to resolved (maybe) element's attribute.
339                 //
340                 // This rule applies to many methods like MoveTo*Attribute().
341                 private bool CheckAndResetEntityReaderOnMoveToAttribute ()
342                 {
343                         if (entityReader == null)
344                                 return false;
345
346                         if (current != null && current.ParentNode != null &&
347                                 current.ParentNode.NodeType == XmlNodeType.Attribute) {
348                                 entityReader.Close ();
349                                 entityReader = entityReaderStack.Count > 0 ?
350                                         entityReaderStack.Pop () as XmlTextReader : null;
351                                 return true;
352                         }
353                         else
354                                 return false;
355                 }
356
357                 public override void Close ()
358                 {
359                         if (entityReader != null)
360                                 entityReader.Close ();
361                         while (entityReaderStack.Count > 0)
362                                 ((XmlTextReader) entityReaderStack.Pop ()).Close ();
363
364                         current = null;
365                         state = ReadState.Closed;
366                 }
367
368                 public override string GetAttribute (int attributeIndex)
369                 {
370                         if (entityReader != null && entityReader.ReadState != ReadState.Initial)
371                                 return entityReader.GetAttribute (attributeIndex);
372
373                         if (NodeType == XmlNodeType.XmlDeclaration) {
374                                 XmlDeclaration decl = current as XmlDeclaration;
375                                 if (attributeIndex == 0)
376                                         return decl.Version;
377                                 else if (attributeIndex == 1) {
378                                         if (decl.Encoding != String.Empty)
379                                                 return decl.Encoding;
380                                         else if (decl.Standalone != String.Empty)
381                                                 return decl.Standalone;
382                                 }
383                                 else if (attributeIndex == 2 &&
384                                                 decl.Encoding != String.Empty && decl.Standalone != null)
385                                         return decl.Standalone;
386                                 throw new ArgumentOutOfRangeException ("Index out of range.");
387                         } else if (NodeType == XmlNodeType.DocumentType) {
388                                 XmlDocumentType doctype = current as XmlDocumentType;
389                                 if (attributeIndex == 0) {
390                                         if (doctype.PublicId != "")
391                                                 return doctype.PublicId;
392                                         else if (doctype.SystemId != "")
393                                                 return doctype.SystemId;
394                                 } else if (attributeIndex == 1)
395                                         if (doctype.PublicId == "" && doctype.SystemId != "")
396                                                 return doctype.SystemId;
397                                 throw new ArgumentOutOfRangeException ("Index out of range.");
398                         }
399
400                         // This is MS.NET bug which returns attributes in spite of EndElement.
401                         if (isEndElement || current == null)
402                                 return null;
403
404                         if (attributeIndex < 0 || attributeIndex > AttributeCount)
405                                 throw new ArgumentOutOfRangeException ("Index out of range.");
406
407                         return ownerElement.Attributes [attributeIndex].Value;
408                 }
409
410                 public override string GetAttribute (string name)
411                 {
412                         if (entityReader != null && entityReader.ReadState != ReadState.Initial)
413                                 return entityReader.GetAttribute (name);
414
415                         // This is MS.NET bug which returns attributes in spite of EndElement.
416                         if (isEndElement || current == null)
417                                 return null;
418
419                         if (NodeType == XmlNodeType.XmlDeclaration)
420                                 return GetXmlDeclarationAttribute (name);
421                         else if (NodeType == XmlNodeType.DocumentType)
422                                 return GetDocumentTypeAttribute (name);
423
424                         XmlAttribute attr = ownerElement.Attributes [name];
425                         if (attr == null)
426                                 return null;
427                         else
428                                 return attr.Value;
429                 }
430
431                 public override string GetAttribute (string name, string namespaceURI)
432                 {
433                         if (entityReader != null && entityReader.ReadState != ReadState.Initial)
434                                 return entityReader.GetAttribute (name, namespaceURI);
435
436                         // This is MS.NET bug which returns attributes in spite of EndElement.
437                         if (isEndElement || current == null)
438                                 return null;
439
440                         if (NodeType == XmlNodeType.XmlDeclaration)
441                                 return GetXmlDeclarationAttribute (name);
442                         else if (NodeType == XmlNodeType.DocumentType)
443                                 return GetDocumentTypeAttribute (name);
444
445                         XmlAttribute attr = ownerElement.Attributes [name, namespaceURI];
446                         if (attr == null)
447                                 return null;    // In fact MS.NET returns null instead of String.Empty.
448                         else
449                                 return attr.Value;
450                 }
451
452                 private string GetXmlDeclarationAttribute (string name)
453                 {
454                         XmlDeclaration decl = current as XmlDeclaration;
455                         switch (name) {
456                         case "version":
457                                 return decl.Version;
458                         case "encoding":
459                                 // This is MS.NET bug that XmlNodeReturns in case of string.empty.
460                                 return decl.Encoding != String.Empty ? decl.Encoding : null;
461                         case "standalone":
462                                 return decl.Standalone;
463                         }
464                         return null;
465                 }
466
467                 private string GetDocumentTypeAttribute (string name)
468                 {
469                         XmlDocumentType doctype = current as XmlDocumentType;
470                         switch (name) {
471                         case "PUBLIC":
472                                 return doctype.PublicId;
473                         case "SYSTEM":
474                                 return doctype.SystemId;
475                         }
476                         return null;
477                 }
478
479                 internal XmlParserContext GetInternalParserContext ()
480                 {
481                         if (entityReader != null)
482                                 return entityReader.GetInternalParserContext ();
483                         else
484                                 return new XmlParserContext (document.NameTable,
485                                         current.ConstructNamespaceManager (),
486                                         XmlLang, XmlSpace);
487                 }
488
489                 public override string LookupNamespace (string prefix)
490                 {
491                         if (entityReader != null && entityReader.ReadState != ReadState.Initial)
492                                 return entityReader.LookupNamespace (prefix);
493
494                         if (current == null)
495                                 return null;
496
497                         XmlAttribute curAttr = current as XmlAttribute;
498                         XmlNode target = curAttr != null ? curAttr.OwnerElement : current;
499
500                         if (prefix == "") {
501                                 do {
502                                         XmlAttribute attr = target.Attributes ["xmlns"];
503                                         if (attr != null)
504                                                 return attr.Value;
505                                         target = target.ParentNode;
506                                 } while (target.NodeType != XmlNodeType.Document);
507                         } else {
508                                 string name = "xmlns:" + prefix;
509                                 do {
510                                         XmlAttribute attr = target.Attributes [name];
511                                         if (attr != null)
512                                                 return attr.Value;
513                                         target = target.ParentNode;
514                                 } while (target.NodeType != XmlNodeType.Document);
515                         }
516                         return defaultNsmgr.LookupNamespace (prefix);
517                 }
518
519                 public override void MoveToAttribute (int attributeIndex)
520                 {
521                         if (entityReader != null) {
522                                 if (!this.CheckAndResetEntityReaderOnMoveToAttribute ()) {
523                                         entityReader.MoveToAttribute (attributeIndex);
524                                         return;
525                                 }
526                                 // And in case of abondoning entityReader, go on...
527                         }
528
529                         if (isEndElement || attributeIndex < 0 || attributeIndex > AttributeCount)
530                                 throw new ArgumentOutOfRangeException ();
531                         
532                         state = ReadState.Interactive;
533                         current = ownerElement.Attributes [attributeIndex];
534                 }
535
536                 public override bool MoveToAttribute (string name)
537                 {
538                         if (entityReader != null) {
539                                 if (!this.CheckAndResetEntityReaderOnMoveToAttribute ())
540                                         return entityReader.MoveToAttribute (name);
541                                 // And in case of abondoning entityReader, go on...
542                         }
543
544                         if (isEndElement || current == null)
545                                 return false;
546                         XmlNode tmpCurrent = current;
547                         if (current.ParentNode.NodeType == XmlNodeType.Attribute)
548                                 current = current.ParentNode;
549
550                         XmlAttribute attr = ownerElement.Attributes [name];
551                         if (attr == null) {
552                                 current = tmpCurrent;
553                                 return false;
554                         }
555                         else {
556                                 current = attr;
557                                 return true;
558                         }
559                 }
560
561                 public override bool MoveToAttribute (string name, string namespaceURI)
562                 {
563                         if (entityReader != null) {
564                                 if (!this.CheckAndResetEntityReaderOnMoveToAttribute ())
565                                         return entityReader.MoveToAttribute (name, namespaceURI);
566                                 // And in case of abondoning entityReader, go on...
567                         }
568
569                         if (isEndElement || current == null)
570                                 return false;
571
572                         XmlAttribute attr = ownerElement.Attributes [name, namespaceURI];
573                         if (attr == null)
574                                 return false;
575                         else {
576                                 current = attr;
577                                 return true;
578                         }
579                 }
580
581                 private void MoveToParentElement ()
582                 {
583                         // This is buggy. It is not only the case when EndElement = true.
584                         isEndElement = true;
585                         depth--;
586                         current = current.ParentNode;
587                 }
588
589                 public override bool MoveToElement ()
590                 {
591                         if (entityReader != null) {
592                                 if (!this.CheckAndResetEntityReaderOnMoveToAttribute ())
593                                         return entityReader.MoveToElement ();
594                                 // And in case of abondoning entityReader, go on...
595                         }
596
597                         if (current == null)
598                                 return false;
599                         if (current.NodeType == XmlNodeType.Attribute) {
600                                 current = ((XmlAttribute) current).OwnerElement;
601                                 return true;
602                         } else 
603                                 return false;
604                 }
605
606                 public override bool MoveToFirstAttribute ()
607                 {
608                         if (entityReader != null) {
609                                 if (!this.CheckAndResetEntityReaderOnMoveToAttribute ())
610                                         return entityReader.MoveToFirstAttribute ();
611                                 // And in case of abondoning entityReader, go on...
612                         }
613
614                         if (current == null)
615                                 return false;
616
617                         if(ownerElement.Attributes.Count > 0)
618                         {
619                                 current = ownerElement.Attributes [0];
620                                 return true;
621                         }
622                         else
623                                 return false;
624                 }
625
626                 public override bool MoveToNextAttribute ()
627                 {
628                         if (entityReader != null) {
629                                 if (!this.CheckAndResetEntityReaderOnMoveToAttribute ())
630                                         return entityReader.MoveToNextAttribute ();
631                                 // And in case of abondoning entityReader, go on...
632                         }
633
634                         if (current == null)
635                                 return false;
636
637                         if (current.NodeType != XmlNodeType.Attribute)
638                                 return MoveToFirstAttribute ();
639                         else
640                         {
641                                 XmlAttributeCollection ac = ((XmlAttribute) current).OwnerElement.Attributes;
642                                 for (int i=0; i<ac.Count-1; i++)
643                                 {
644                                         XmlAttribute attr = ac [i];
645                                         if (attr == current)
646                                         {
647                                                 i++;
648                                                 if (i == ac.Count)
649                                                         return false;
650                                                 current = ac [i];
651                                                 return true;
652                                         }
653                                 }
654                                 return false;
655                         }
656                 }
657
658                 private bool MoveToNextSibling ()
659                 {
660                         if (nextIsEndElement) {
661                                 // nextIsEndElement is set only by ReadString.
662                                 nextIsEndElement = false;
663                                 MoveToParentElement ();
664                         } else if (alreadyRead) {
665                                 alreadyRead = false;
666                                 return current != null;
667                         }
668                         if (current.NextSibling != null) {
669                                 isEndElement = false;
670                                 current = current.NextSibling;
671                         } else {
672                                 MoveToParentElement ();
673                         }
674                         if (current == null) {
675                                 state = ReadState.EndOfFile;
676                                 return false;
677                         }
678                         else
679                                 return true;
680                 }
681
682                 public override bool Read ()
683                 {
684                         if (EOF)
685                                 return false;
686
687                         this.CheckAndResetEntityReaderOnMoveToAttribute ();
688                         if (entityReader != null) {
689                                 // Read finalizes entity reader.
690                                 switch (entityReader.ReadState) {
691                                 case ReadState.Interactive:
692                                 case ReadState.Initial:
693                                         // If it is ended, then other properties/methods will take care.
694                                         entityReader.Read ();
695                                         return true;
696                                 default:
697                                         entityReader = entityReaderStack.Count > 0 ?
698                                                 entityReaderStack.Pop () as XmlTextReader : null;
699                                         return Read ();
700                                 }
701                                 // and go on ...
702                         }
703
704                         if (ReadState == ReadState.Initial) {
705                                 current = startNode;
706                                 state = ReadState.Interactive;
707                                 // when startNode is document or fragment
708                                 if (!alreadyRead)
709                                         current = startNode.FirstChild;
710                                 else
711                                         alreadyRead = false;
712                                 if (current == null) {
713                                         state = ReadState.Error;
714                                         return false;
715                                 } else
716                                         return true;
717                         }
718
719                         MoveToElement ();
720
721                         if (IsEmptyElement || isEndElement) {
722                                 // Then go up and move to next.
723                                 // If no more nodes, then set EOF.
724                                 isEndElement = false;
725                                 if (current.ParentNode == null
726                                         || current.ParentNode.NodeType == XmlNodeType.Document
727                                         || current.ParentNode.NodeType == XmlNodeType.DocumentFragment) {
728                                         current = null;
729                                         state = ReadState.EndOfFile;
730                                         return false;
731                                 } else if (current.NextSibling == null) {
732                                         depth--;
733                                         current = current.ParentNode;
734                                         isEndElement = true;
735                                         return true;
736                                 } else {
737                                         current = current.NextSibling;
738                                         return true;
739                                 }
740
741                         } else if (nextIsEndElement) {
742                                 // nextIsEndElement is set only by ReadString.
743                                 nextIsEndElement = false;
744                                 isEndElement = true;
745                                 return current != null;
746
747                         } else if (alreadyRead) {
748                                 alreadyRead = false;
749                                 return current != null;
750                         }
751
752                         if (!isEndElement && current.FirstChild != null) {
753                                 isEndElement = false;
754                                 current = current.FirstChild;
755                                 depth++;
756                         } else if (current.NodeType == XmlNodeType.Element) {
757                                 isEndElement = true;
758                                 if (current.FirstChild != null)
759                                         depth--;
760                         } else
761                                 MoveToNextSibling ();
762
763                         return current != null;
764                 }
765
766                 public override bool ReadAttributeValue ()
767                 {
768                         if (entityReader != null) {
769                                 switch (entityReader.ReadState) {
770                                 case ReadState.Interactive:
771                                 case ReadState.Initial:
772                                         // If it is ended, then other properties/methods will take care.
773                                         return entityReader.ReadAttributeValue ();
774                                 default:
775                                         entityReader = entityReaderStack.Count > 0 ?
776                                                 entityReaderStack.Pop () as XmlTextReader : null;
777                                         // and go on ...
778                                         return ReadAttributeValue ();
779                                 }
780                         }
781
782                         if (current.NodeType == XmlNodeType.Attribute) {
783                                 current = current.FirstChild;
784                                 return current != null;
785                         } else if (current.ParentNode.NodeType == XmlNodeType.Attribute) {
786                                 if (current.NextSibling == null)
787                                         return false;
788                                 current = current.NextSibling;
789                                 return true;
790                         } else
791                                 return false;
792                 }
793
794 #if NET_1_0
795                 // Its traversal behavior is almost same as Read().
796                 public override string ReadInnerXml ()
797                 {
798                         if (entityReader != null) {
799                                 if (entityReader.EOF) {
800                                         entityReader = entityReaderStack.Count > 0 ?
801                                                 entityReaderStack.Pop () as XmlTextReader : null;
802                                         return ReadInnerXml ();
803                                 } else
804                                         return entityReader.ReadInnerXml ();
805                         }
806
807                         if (this.state != ReadState.Interactive)
808                                 return String.Empty;
809
810                         XmlNode initial = current;
811                         // Almost copied from XmlTextReader.
812                         switch (NodeType) {
813                         case XmlNodeType.Attribute:
814                                 return Value;
815                         case XmlNodeType.Element:
816                                 if (IsEmptyElement)
817                                         return String.Empty;
818
819                                 int startDepth = depth;
820
821                                 bool loop = true;
822                                 do {
823                                         Read ();
824                                         if (NodeType ==XmlNodeType.None)
825                                                 throw new XmlException ("unexpected end of xml.");
826                                         else if (NodeType == XmlNodeType.EndElement && depth == startDepth) {
827                                                 loop = false;
828                                                 Read ();
829                                         }
830                                 } while (loop);
831                                 return initial.InnerXml;
832                         case XmlNodeType.None:
833                                 return String.Empty;
834                         default:
835                                 Read ();
836                                 return String.Empty;
837                         }
838                 }
839
840                 // Its traversal behavior is almost same as Read().
841                 public override string ReadOuterXml ()
842                 {
843                         if (entityReader != null) {
844                                 if (entityReader.EOF) {
845                                         entityReader = entityReaderStack.Count > 0 ?
846                                                 entityReaderStack.Pop () as XmlTextReader : null;
847                                         return ReadOuterXml ();
848                                 } else
849                                         return entityReader.ReadOuterXml ();
850                         }
851
852                         if (NodeType == XmlNodeType.EndElement)
853                                 return String.Empty;
854                         XmlNode initial = current;
855
856                         switch (NodeType) {
857                         case XmlNodeType.Attribute:
858                                 return current.OuterXml;
859                         case XmlNodeType.Element:
860                                 if (NodeType == XmlNodeType.Element && !IsEmptyElement)
861                                         ReadInnerXml ();
862                                 else
863                                         Read ();
864                                 return initial.OuterXml;
865                         case XmlNodeType.None:
866                                 return String.Empty;
867                         default:
868                                 Read ();
869                                 return String.Empty;
870                         }
871                 }
872 #endif
873
874                 public override string ReadString ()
875                 {
876                         return ReadStringInternal ();
877                 }
878
879                 public override void ResolveEntity ()
880                 {
881                         if (NodeType != XmlNodeType.EntityReference)
882                                 throw new InvalidOperationException ("The current node is not an Entity Reference");
883                         XmlEntity entity = document.DocumentType != null ?
884                                 document.DocumentType.Entities.GetNamedItem (Name) as XmlEntity : null;
885
886                         // MS.NET seems simply ignoring undeclared entity reference ;-(
887                         string replacementText =
888                                 (entity != null) ? entity.InnerText : String.Empty;
889
890                         XmlNodeType xmlReaderNodeType = 
891                                 (current.ParentNode != null && current.ParentNode.NodeType == XmlNodeType.Attribute) ?
892                                 XmlNodeType.Attribute : XmlNodeType.Element;
893
894                         XmlParserContext ctx = null;
895                         if (entityReader != null) {
896                                 entityReaderStack.Push (entityReader);
897                                 ctx = entityReader.GetInternalParserContext ();
898                         }
899                         if (ctx == null) {
900                                 ctx = new XmlParserContext (document.NameTable,
901                                         current.ConstructNamespaceManager (),
902                                         document.DocumentType != null ? document.DocumentType.DTD : null,
903                                         BaseURI, XmlLang, XmlSpace, Encoding.Unicode);
904                         }
905                         entityReader = new XmlTextReader (replacementText, xmlReaderNodeType, ctx);
906                         entityReader.MaybeTextDecl = true;
907                 }
908
909                 public override void Skip ()
910                 {
911                         // Why is this overriden? Such skipping might raise
912                         // (or ignore) unexpected validation error.
913                         base.Skip ();
914                 }
915                 #endregion
916         }
917 }