Merge pull request #823 from DavidKarlas/master
[mono.git] / mcs / class / System.XML / System.Xml / XmlNodeReaderImpl.cs
1 //
2 // System.Xml.XmlNodeReaderImpl.cs - implements the core part of XmlNodeReader
3 //
4 // Author:
5 //      Atsushi Enomoto  (atsushi@ximian.com)
6 //
7 // (C) 2004 Novell Inc.
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 //
32 // This serves the implementation part of XmlNodeReader except for
33 // ResolveEntity().
34 //
35
36 using System;
37 #if NET_2_0
38 using System.Collections.Generic;
39 #endif
40 using System.Xml;
41 using System.Text;
42 using Mono.Xml;
43 #if NET_2_0
44 using System.Xml.Schema;
45 #endif
46
47 namespace System.Xml
48 {
49 #if NET_2_0
50         internal class XmlNodeReaderImpl : XmlReader, IHasXmlParserContext, IXmlNamespaceResolver
51 #else
52         internal class XmlNodeReaderImpl : XmlReader, IHasXmlParserContext
53 #endif
54         {
55                 XmlDocument document;
56                 XmlNode startNode;
57                 XmlNode current;
58                 XmlNode ownerLinkedNode;
59                 ReadState state = ReadState.Initial;
60                 int depth;
61                 bool isEndElement;
62                 bool ignoreStartNode;
63
64                 #region Constructor
65
66                 internal XmlNodeReaderImpl (XmlNodeReaderImpl entityContainer)
67                         : this (entityContainer.current)
68                 {
69                 }
70
71                 public XmlNodeReaderImpl (XmlNode node)
72                 {
73                         startNode = node;
74                         depth = 0;
75                         document = startNode.NodeType == XmlNodeType.Document ?
76                                 startNode as XmlDocument : startNode.OwnerDocument;
77
78                         switch (node.NodeType) {
79                         case XmlNodeType.Document:
80                         case XmlNodeType.DocumentFragment:
81                         case XmlNodeType.EntityReference:
82                                 ignoreStartNode = true;
83                                 break;
84                         }
85
86                 }
87                 
88                 #endregion
89
90                 #region Properties
91
92                 public override int AttributeCount {
93                         get {
94                                 if (state != ReadState.Interactive)
95                                         return 0;
96
97                                 if (isEndElement || current == null)
98                                         return 0;
99                                 XmlNode n = ownerLinkedNode;
100                                 return n.Attributes != null ? n.Attributes.Count : 0;
101                         }
102                 }
103
104                 public override string BaseURI {
105                         get {
106                                 if (current == null)
107                                         return startNode.BaseURI;
108                                 return current.BaseURI;
109                         }
110                 }
111
112 #if NET_2_0
113                 public override bool CanReadBinaryContent {
114                         get { return true; }
115                 }
116
117                 public override bool CanReadValueChunk {
118                         get { return true; }
119                 }
120 #else
121                 internal override bool CanReadBinaryContent {
122                         get { return true; }
123                 }
124
125                 internal override bool CanReadValueChunk {
126                         get { return true; }
127                 }
128 #endif
129
130                 public override bool CanResolveEntity {
131                         get { return false; }
132                 }
133
134                 public override int Depth {
135                         get {
136                                 return current == null ? 0 :
137                                         current == ownerLinkedNode ? depth :
138                                         current.NodeType == XmlNodeType.Attribute ? depth + 1 :
139                                         depth + 2;
140                         }
141                 }
142
143                 public override bool EOF {
144                         get { return state == ReadState.EndOfFile || state == ReadState.Error; }
145                 }
146
147                 public override bool HasAttributes {
148                         get {
149                                 if (isEndElement || current == null)
150                                         return false;
151
152                                 // MS BUG: inconsistent return value between XmlTextReader and XmlNodeReader.
153                                 // As for attribute and its descendants, XmlReader returns element's HasAttributes.
154                                 XmlNode n = ownerLinkedNode;
155
156                                 if (n.Attributes == null ||
157                                         n.Attributes.Count == 0)
158                                         return false;
159                                 else
160                                         return true;
161                         }
162                 }
163
164                 public override bool HasValue {
165                         get {
166                                 if (current == null)
167                                         return false;
168
169                                 switch (current.NodeType) {
170                                 case XmlNodeType.Element:
171                                 case XmlNodeType.EntityReference:
172                                 case XmlNodeType.Document:
173                                 case XmlNodeType.DocumentFragment:
174                                 case XmlNodeType.Notation:
175                                 case XmlNodeType.EndElement:
176                                 case XmlNodeType.EndEntity:
177                                         return false;
178                                 default:
179                                         return true;
180                                 }
181                         }
182                               
183                 }
184
185                 public override bool IsDefault {
186                         get {
187                                 if (current == null)
188                                         return false;
189
190                                 if (current.NodeType != XmlNodeType.Attribute)
191                                         return false;
192                                 else
193                                 {
194                                         return !((XmlAttribute) current).Specified;
195                                 }
196                         }
197                 }
198
199                 public override bool IsEmptyElement {
200                         get {
201                                 if (current == null)
202                                         return false;
203
204                                 if(current.NodeType == XmlNodeType.Element)
205                                         return ((XmlElement) current).IsEmpty;
206                                 else 
207                                         return false;
208                         }
209                 }
210
211 #if NET_2_0
212 #else
213                 public override string this [int i] {
214                         get { return GetAttribute (i); }
215                 }
216
217                 public override string this [string name] {
218                         get { return GetAttribute (name); }
219                 }
220
221                 public override string this [string name, string namespaceURI] {
222                         get { return GetAttribute (name, namespaceURI); }
223                 }
224 #endif
225
226                 public override string LocalName {
227                         get {
228                                 if (current == null)
229                                         return String.Empty;
230
231                                 switch (current.NodeType) {
232                                 case XmlNodeType.Attribute:
233                                 case XmlNodeType.DocumentType:
234                                 case XmlNodeType.Element:
235                                 case XmlNodeType.EntityReference:
236                                 case XmlNodeType.ProcessingInstruction:
237                                 case XmlNodeType.XmlDeclaration:
238                                         return current.LocalName;
239                                 }
240
241                                 return String.Empty;
242                         }
243                 }
244
245                 public override string Name {
246                         get {
247                                 if (current == null)
248                                         return String.Empty;
249
250                                 switch (current.NodeType) {
251                                 case XmlNodeType.Attribute:
252                                 case XmlNodeType.DocumentType:
253                                 case XmlNodeType.Element:
254                                 case XmlNodeType.EntityReference:
255                                 case XmlNodeType.ProcessingInstruction:
256                                 case XmlNodeType.XmlDeclaration:
257                                         return current.Name;
258                                 }
259
260                                 return String.Empty;
261                         }
262                 }
263
264                 public override string NamespaceURI {
265                         get {
266                                 if (current == null)
267                                         return String.Empty;
268
269                                 return current.NamespaceURI;
270                         }
271                 }
272
273                 public override XmlNameTable NameTable {
274                         get { return document.NameTable; }
275                 }
276
277                 public override XmlNodeType NodeType {
278                         get {
279                                 if (current == null)
280                                         return XmlNodeType.None;
281
282                                 return isEndElement ? XmlNodeType.EndElement : current.NodeType;
283                         }
284                 }
285
286                 public override string Prefix {
287                         get { 
288                                 if (current == null)
289                                         return String.Empty;
290
291                                 return current.Prefix;
292                         }
293                 }
294
295 #if NET_2_0
296 #else
297                 public override char QuoteChar {
298                         get {
299                                 return '"';
300                         }
301                 }
302 #endif
303
304                 public override ReadState ReadState {
305                         get { return state; }
306                 }
307
308 #if NET_2_0
309                 public override IXmlSchemaInfo SchemaInfo {
310                         get { return current != null ? current.SchemaInfo : null; }
311                 }
312 #endif
313
314                 public override string Value {
315                         get {
316                                 if (NodeType == XmlNodeType.DocumentType)
317                                         return ((XmlDocumentType) current).InternalSubset;
318                                 else
319                                         return HasValue ? current.Value : String.Empty;
320                         }
321                 }
322
323                 public override string XmlLang {
324                         get {
325                                 if (current == null)
326                                         return startNode.XmlLang;
327
328                                 return current.XmlLang;
329                         }
330                 }
331
332                 public override XmlSpace XmlSpace {
333                         get {
334                                 if (current == null)
335                                         return startNode.XmlSpace;
336
337                                 return current.XmlSpace;
338                         }
339                 }
340                 #endregion
341
342                 #region Methods
343
344                 public override void Close ()
345                 {
346                         current = null;
347                         state = ReadState.Closed;
348                 }
349
350                 public override string GetAttribute (int attributeIndex)
351                 {
352                         if (NodeType == XmlNodeType.XmlDeclaration) {
353                                 XmlDeclaration decl = current as XmlDeclaration;
354                                 if (attributeIndex == 0)
355                                         return decl.Version;
356                                 else if (attributeIndex == 1) {
357                                         if (decl.Encoding != String.Empty)
358                                                 return decl.Encoding;
359                                         else if (decl.Standalone != String.Empty)
360                                                 return decl.Standalone;
361                                 }
362                                 else if (attributeIndex == 2 &&
363                                                 decl.Encoding != String.Empty && decl.Standalone != null)
364                                         return decl.Standalone;
365                                 throw new ArgumentOutOfRangeException ("Index out of range.");
366                         } else if (NodeType == XmlNodeType.DocumentType) {
367                                 XmlDocumentType doctype = current as XmlDocumentType;
368                                 if (attributeIndex == 0) {
369                                         if (doctype.PublicId != "")
370                                                 return doctype.PublicId;
371                                         else if (doctype.SystemId != "")
372                                                 return doctype.SystemId;
373                                 } else if (attributeIndex == 1)
374                                         if (doctype.PublicId == "" && doctype.SystemId != "")
375                                                 return doctype.SystemId;
376                                 throw new ArgumentOutOfRangeException ("Index out of range.");
377                         }
378
379                         // This is MS.NET bug which returns attributes in spite of EndElement.
380                         if (isEndElement || current == null)
381                                 return null;
382
383                         if (attributeIndex < 0 || attributeIndex > AttributeCount)
384                                 throw new ArgumentOutOfRangeException ("Index out of range.");
385
386                         return ownerLinkedNode.Attributes [attributeIndex].Value;
387                 }
388
389                 public override string GetAttribute (string name)
390                 {
391                         // This is MS.NET bug which returns attributes in spite of EndElement.
392                         if (isEndElement || current == null)
393                                 return null;
394
395                         if (NodeType == XmlNodeType.XmlDeclaration)
396                                 return GetXmlDeclarationAttribute (name);
397                         else if (NodeType == XmlNodeType.DocumentType)
398                                 return GetDocumentTypeAttribute (name);
399
400                         if (ownerLinkedNode.Attributes == null)
401                                 return null;
402                         XmlAttribute attr = ownerLinkedNode.Attributes [name];
403                         if (attr == null)
404                                 return null;
405                         else
406                                 return attr.Value;
407                 }
408
409                 public override string GetAttribute (string name, string namespaceURI)
410                 {
411                         // This is MS.NET bug which returns attributes in spite of EndElement.
412                         if (isEndElement || current == null)
413                                 return null;
414
415                         if (NodeType == XmlNodeType.XmlDeclaration)
416                                 return GetXmlDeclarationAttribute (name);
417                         else if (NodeType == XmlNodeType.DocumentType)
418                                 return GetDocumentTypeAttribute (name);
419
420                         if (ownerLinkedNode.Attributes == null)
421                                 return null;
422                         XmlAttribute attr = ownerLinkedNode.Attributes [name, namespaceURI];
423                         if (attr == null)
424                                 return null;    // In fact MS.NET returns null instead of String.Empty.
425                         else
426                                 return attr.Value;
427                 }
428
429                 private string GetXmlDeclarationAttribute (string name)
430                 {
431                         XmlDeclaration decl = current as XmlDeclaration;
432                         switch (name) {
433                         case "version":
434                                 return decl.Version;
435                         case "encoding":
436                                 // This is MS.NET bug that XmlNodeReturns in case of string.empty.
437                                 return decl.Encoding != String.Empty ? decl.Encoding : null;
438                         case "standalone":
439                                 return decl.Standalone;
440                         }
441                         return null;
442                 }
443
444                 private string GetDocumentTypeAttribute (string name)
445                 {
446                         XmlDocumentType doctype = current as XmlDocumentType;
447                         switch (name) {
448                         case "PUBLIC":
449                                 return doctype.PublicId;
450                         case "SYSTEM":
451                                 return doctype.SystemId;
452                         }
453                         return null;
454                 }
455
456                 XmlParserContext IHasXmlParserContext.ParserContext {
457                         get {
458                                 return new XmlParserContext (document.NameTable,
459                                         current == null ?
460                                                 new XmlNamespaceManager (document.NameTable) :
461                                                 current.ConstructNamespaceManager (),
462                                         document.DocumentType != null ? document.DocumentType.DTD : null,
463                                         current == null ? document.BaseURI : current.BaseURI,
464                                         XmlLang, XmlSpace, Encoding.Unicode);
465                         }
466                 }
467
468 #if NET_2_0
469                 public IDictionary<string, string> GetNamespacesInScope (XmlNamespaceScope scope)
470                 {
471                         IDictionary<string, string> table = new Dictionary<string, string> ();
472                         XmlNode n = current ?? startNode;
473                         do {
474                                 if (n.NodeType == XmlNodeType.Document)
475                                         break;
476                                 for (int i = 0; i < n.Attributes.Count; i++) {
477                                         XmlAttribute a = n.Attributes [i];
478                                         if (a.NamespaceURI == XmlNamespaceManager.XmlnsXmlns) {
479                                                 string key = a.Prefix == XmlNamespaceManager.PrefixXmlns ? a.LocalName : String.Empty;
480                                                 if (!table.ContainsKey (key))
481                                                         table.Add (key, a.Value);
482                                         }
483                                 }
484                                 if (scope == XmlNamespaceScope.Local)
485                                         return table;
486                                 n = n.ParentNode;
487                         } while (n != null);
488                         if (scope == XmlNamespaceScope.All)
489                                 table.Add (XmlNamespaceManager.PrefixXml, XmlNamespaceManager.XmlnsXml);
490                         return table;
491                 }
492 #endif
493
494                 private XmlElement GetCurrentElement ()
495                 {
496                         XmlElement el = null;
497                         switch (current.NodeType) {
498                         case XmlNodeType.Attribute:
499                                 el = ((XmlAttribute) current).OwnerElement;
500                                 break;
501                         case XmlNodeType.Element:
502                                 el = (XmlElement) current;
503                                 break;
504                         case XmlNodeType.Text:
505                         case XmlNodeType.CDATA:
506                         case XmlNodeType.EntityReference:
507                         case XmlNodeType.Comment:
508                         case XmlNodeType.SignificantWhitespace:
509                         case XmlNodeType.Whitespace:
510                         case XmlNodeType.ProcessingInstruction:
511                                 el = current.ParentNode as XmlElement;
512                                 break;
513                         }
514                         return el;
515                 }
516
517                 public override string LookupNamespace (string prefix)
518                 {
519                         if (current == null)
520                                 return null;
521
522                         XmlElement el = GetCurrentElement ();
523
524                         for (; el != null; el = el.ParentNode as XmlElement) {
525                                 for (int i = 0; i < el.Attributes.Count; i++) {
526                                         XmlAttribute attr = el.Attributes [i];
527                                         if (attr.NamespaceURI != XmlNamespaceManager.XmlnsXmlns)
528                                                 continue;
529                                         if (prefix == "") {
530                                                 if (attr.Prefix == "")
531                                                         return attr.Value;
532                                         }
533                                         else if (attr.LocalName == prefix)
534                                                 return attr.Value;
535                                         continue;
536                                 }
537                         }
538
539                         switch (prefix) {
540                         case XmlNamespaceManager.PrefixXml:
541                                 return XmlNamespaceManager.XmlnsXml;
542                         case XmlNamespaceManager.PrefixXmlns:
543                                 return XmlNamespaceManager.XmlnsXmlns;
544                         }
545                         return null;
546                 }
547
548 #if NET_2_0
549                 public string LookupPrefix (string ns)
550                 {
551                         return LookupPrefix (ns, false);
552                 }
553
554                 public string LookupPrefix (string ns, bool atomizedNames)
555                 {
556                         if (current == null)
557                                 return null;
558
559                         XmlElement el = GetCurrentElement ();
560
561                         for (; el != null; el = el.ParentNode as XmlElement) {
562                                 for (int i = 0; i < el.Attributes.Count; i++) {
563                                         XmlAttribute attr = el.Attributes [i];
564                                         if (atomizedNames) {
565                                                 if (!Object.ReferenceEquals (attr.NamespaceURI, XmlNamespaceManager.XmlnsXmlns))
566                                                         continue;
567                                                 if (Object.ReferenceEquals (attr.Value, ns))
568                                                         // xmlns:blah="..." -> LocalName, xmlns="..." -> String.Empty
569                                                         return attr.Prefix != String.Empty ? attr.LocalName : String.Empty;
570                                         } else {
571                                                 if (attr.NamespaceURI != XmlNamespaceManager.XmlnsXmlns)
572                                                         continue;
573                                                 if (attr.Value == ns)
574                                                         // xmlns:blah="..." -> LocalName, xmlns="..." -> String.Empty
575                                                         return attr.Prefix != String.Empty ? attr.LocalName : String.Empty;
576                                         }
577                                 }
578                         }
579                         switch (ns) {
580                         case XmlNamespaceManager.XmlnsXml:
581                                 return XmlNamespaceManager.PrefixXml;
582                         case XmlNamespaceManager.XmlnsXmlns:
583                                 return XmlNamespaceManager.PrefixXmlns;
584                         }
585                         return null;
586                 }
587 #endif
588
589                 public override void MoveToAttribute (int attributeIndex)
590                 {
591                         if (isEndElement || attributeIndex < 0 || attributeIndex > AttributeCount)
592                                 throw new ArgumentOutOfRangeException ();
593                         
594                         state = ReadState.Interactive;
595                         current = ownerLinkedNode.Attributes [attributeIndex];
596                 }
597
598                 public override bool MoveToAttribute (string name)
599                 {
600                         if (isEndElement || current == null)
601                                 return false;
602                         XmlNode tmpCurrent = current;
603                         if (current.ParentNode.NodeType == XmlNodeType.Attribute)
604                                 current = current.ParentNode;
605
606                         if (ownerLinkedNode.Attributes == null)
607                                 return false;
608                         XmlAttribute attr = ownerLinkedNode.Attributes [name];
609                         if (attr == null) {
610                                 current = tmpCurrent;
611                                 return false;
612                         }
613                         else {
614                                 current = attr;
615                                 return true;
616                         }
617                 }
618
619                 public override bool MoveToAttribute (string name, string namespaceURI)
620                 {
621                         if (isEndElement || current == null)
622                                 return false;
623
624                         if (ownerLinkedNode.Attributes == null)
625                                 return false;
626                         XmlAttribute attr = ownerLinkedNode.Attributes [name, namespaceURI];
627                         if (attr == null)
628                                 return false;
629                         else {
630                                 current = attr;
631                                 return true;
632                         }
633                 }
634
635                 public override bool MoveToElement ()
636                 {
637                         if (current == null)
638                                 return false;
639                         XmlNode n = ownerLinkedNode;
640                         if (current != n) {
641                                 current = n;
642                                 return true;
643                         } else 
644                                 return false;
645                 }
646
647                 public override bool MoveToFirstAttribute ()
648                 {
649                         if (current == null)
650                                 return false;
651
652                         if (ownerLinkedNode.Attributes == null)
653                                 return false;
654                         if(ownerLinkedNode.Attributes.Count > 0)
655                         {
656                                 current = ownerLinkedNode.Attributes [0];
657                                 return true;
658                         }
659                         else
660                                 return false;
661                 }
662
663                 public override bool MoveToNextAttribute ()
664                 {
665                         if (current == null)
666                                 return false;
667
668                         XmlNode anode = current;
669                         if (current.NodeType != XmlNodeType.Attribute) {
670                                 // then it's either an attribute child or anything on the tree.
671                                 if (current.ParentNode == null ||  // document, or non-tree node
672                                     current.ParentNode.NodeType != XmlNodeType.Attribute) // not an attr value
673                                         return MoveToFirstAttribute ();
674                                 anode = current.ParentNode;
675                         }
676
677                         {
678                                 XmlAttributeCollection ac = ((XmlAttribute) anode).OwnerElement.Attributes;
679                                 for (int i=0; i<ac.Count-1; i++)
680                                 {
681                                         XmlAttribute attr = ac [i];
682                                         if (attr == anode)
683                                         {
684                                                 i++;
685                                                 if (i == ac.Count)
686                                                         return false;
687                                                 current = ac [i];
688                                                 return true;
689                                         }
690                                 }
691                                 return false;
692                         }
693                 }
694
695                 public override bool Read ()
696                 {
697                         // FIXME: at some stage inlining might work effectively.
698                         // if (EOF)
699                         switch (state) {
700                         case ReadState.EndOfFile:
701                         case ReadState.Error:
702                         case ReadState.Closed:
703                                 return false;
704                         }
705
706 #if NET_2_0
707                         if (Binary != null)
708                                 Binary.Reset ();
709 #endif
710
711                         bool ret = ReadContent ();
712                         ownerLinkedNode = current;
713                         return ret;
714                 }
715
716                 bool ReadContent ()
717                 {
718                         if (ReadState == ReadState.Initial) {
719                                 current = startNode;
720                                 state = ReadState.Interactive;
721                                 // when startNode is document or fragment
722                                 if (ignoreStartNode)
723                                         current = startNode.FirstChild;
724                                 if (current == null) {
725                                         state = ReadState.Error;
726                                         return false;
727                                 } else
728                                         return true;
729                         }
730
731                         MoveToElement ();
732
733                         // don't step into EntityReference's children. Also
734                         // avoid re-entering children of already-consumed
735                         // element (i.e. when it is regarded as EndElement).
736                         XmlNode firstChild =
737                                 !isEndElement && current.NodeType != XmlNodeType.EntityReference ?
738                                 current.FirstChild : null;
739                         if (firstChild != null) {
740                                 isEndElement = false;
741                                 current = firstChild;
742                                 depth++;
743                                 return true;
744                         }
745
746                         if (current == startNode) { // Currently it is on the start node.
747                                 if (IsEmptyElement || isEndElement) {
748                                         // The start node is already consumed.
749                                         isEndElement = false;
750                                         current = null;
751                                         state = ReadState.EndOfFile;
752                                         return false;
753                                 } else {
754                                         // The start node is the only element
755                                         // which should be processed. Now it
756                                         // is set as EndElement.
757                                         isEndElement = true;
758                                         return true;
759                                 }
760                         }
761                         if (!isEndElement && !IsEmptyElement &&
762                             current.NodeType == XmlNodeType.Element) {
763                                 // element, currently not EndElement, and has
764                                 // no child. (such as <foo></foo>, which
765                                 // should become EndElement).
766                                 isEndElement = true;
767                                 return true;
768                         }
769
770                         // If NextSibling is available, move to there.
771                         XmlNode next = current.NextSibling;
772                         if (next != null) {
773                                 isEndElement = false;
774                                 current = next;
775                                 return true;
776                         }
777
778                         // Otherwise, parent.
779                         XmlNode parent = current.ParentNode;
780                         if (parent == null || parent == startNode && ignoreStartNode) {
781                                 // Parent is not available, or reached to
782                                 // the start node. This reader never sets 
783                                 // startNode as current if it was originally 
784                                 // ignored (e.g. startNode is XmlDocument).
785                                 isEndElement = false;
786                                 current = null;
787                                 state = ReadState.EndOfFile;
788                                 return false;
789                         } else {
790                                 // Parent was available, so return it as
791                                 // EndElement.
792                                 current = parent;
793                                 depth--;
794                                 isEndElement = true;
795                                 return true;
796                         }
797                 }
798
799                 public override bool ReadAttributeValue ()
800                 {
801                         if (current.NodeType == XmlNodeType.Attribute) {
802                                 if (current.FirstChild == null)
803                                         return false;
804                                 current = current.FirstChild;
805                                 return true;
806                         } else if (current.ParentNode.NodeType == XmlNodeType.Attribute) {
807                                 if (current.NextSibling == null)
808                                         return false;
809                                 current = current.NextSibling;
810                                 return true;
811                         } else
812                                 return false;
813                 }
814
815                 public override string ReadString ()
816                 {
817                         return base.ReadString ();
818                 }
819
820                 public override void ResolveEntity ()
821                 {
822                         throw new NotSupportedException ("Should not happen.");
823                 }
824
825                 public override void Skip ()
826                 {
827                         // Why is this overriden? Such skipping might raise
828                         // (or ignore) unexpected validation error.
829                         base.Skip ();
830                 }
831                 #endregion
832         }
833 }