2010-03-12 Jb Evain <jbevain@novell.com>
[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 #if !NET_2_1 || MONOTOUCH
165                 public override bool HasValue {
166                         get {
167                                 if (current == null)
168                                         return false;
169
170                                 switch (current.NodeType) {
171                                 case XmlNodeType.Element:
172                                 case XmlNodeType.EntityReference:
173                                 case XmlNodeType.Document:
174                                 case XmlNodeType.DocumentFragment:
175                                 case XmlNodeType.Notation:
176                                 case XmlNodeType.EndElement:
177                                 case XmlNodeType.EndEntity:
178                                         return false;
179                                 default:
180                                         return true;
181                                 }
182                         }
183                               
184                 }
185 #endif
186
187                 public override bool IsDefault {
188                         get {
189                                 if (current == null)
190                                         return false;
191
192                                 if (current.NodeType != XmlNodeType.Attribute)
193                                         return false;
194                                 else
195                                 {
196                                         return !((XmlAttribute) current).Specified;
197                                 }
198                         }
199                 }
200
201                 public override bool IsEmptyElement {
202                         get {
203                                 if (current == null)
204                                         return false;
205
206                                 if(current.NodeType == XmlNodeType.Element)
207                                         return ((XmlElement) current).IsEmpty;
208                                 else 
209                                         return false;
210                         }
211                 }
212
213 #if NET_2_0
214 #else
215                 public override string this [int i] {
216                         get { return GetAttribute (i); }
217                 }
218
219                 public override string this [string name] {
220                         get { return GetAttribute (name); }
221                 }
222
223                 public override string this [string name, string namespaceURI] {
224                         get { return GetAttribute (name, namespaceURI); }
225                 }
226 #endif
227
228                 public override string LocalName {
229                         get {
230                                 if (current == null)
231                                         return String.Empty;
232
233                                 switch (current.NodeType) {
234                                 case XmlNodeType.Attribute:
235                                 case XmlNodeType.DocumentType:
236                                 case XmlNodeType.Element:
237                                 case XmlNodeType.EntityReference:
238                                 case XmlNodeType.ProcessingInstruction:
239                                 case XmlNodeType.XmlDeclaration:
240                                         return current.LocalName;
241                                 }
242
243                                 return String.Empty;
244                         }
245                 }
246
247                 public override string Name {
248                         get {
249                                 if (current == null)
250                                         return String.Empty;
251
252                                 switch (current.NodeType) {
253                                 case XmlNodeType.Attribute:
254                                 case XmlNodeType.DocumentType:
255                                 case XmlNodeType.Element:
256                                 case XmlNodeType.EntityReference:
257                                 case XmlNodeType.ProcessingInstruction:
258                                 case XmlNodeType.XmlDeclaration:
259                                         return current.Name;
260                                 }
261
262                                 return String.Empty;
263                         }
264                 }
265
266                 public override string NamespaceURI {
267                         get {
268                                 if (current == null)
269                                         return String.Empty;
270
271                                 return current.NamespaceURI;
272                         }
273                 }
274
275                 public override XmlNameTable NameTable {
276                         get { return document.NameTable; }
277                 }
278
279                 public override XmlNodeType NodeType {
280                         get {
281                                 if (current == null)
282                                         return XmlNodeType.None;
283
284                                 return isEndElement ? XmlNodeType.EndElement : current.NodeType;
285                         }
286                 }
287
288                 public override string Prefix {
289                         get { 
290                                 if (current == null)
291                                         return String.Empty;
292
293                                 return current.Prefix;
294                         }
295                 }
296
297 #if NET_2_0
298 #else
299                 public override char QuoteChar {
300                         get {
301                                 return '"';
302                         }
303                 }
304 #endif
305
306                 public override ReadState ReadState {
307                         get { return state; }
308                 }
309
310 #if NET_2_0
311                 public override IXmlSchemaInfo SchemaInfo {
312                         get { return current != null ? current.SchemaInfo : null; }
313                 }
314 #endif
315
316                 public override string Value {
317                         get {
318                                 if (NodeType == XmlNodeType.DocumentType)
319                                         return ((XmlDocumentType) current).InternalSubset;
320                                 else
321                                         return HasValue ? current.Value : String.Empty;
322                         }
323                 }
324
325                 public override string XmlLang {
326                         get {
327                                 if (current == null)
328                                         return startNode.XmlLang;
329
330                                 return current.XmlLang;
331                         }
332                 }
333
334                 public override XmlSpace XmlSpace {
335                         get {
336                                 if (current == null)
337                                         return startNode.XmlSpace;
338
339                                 return current.XmlSpace;
340                         }
341                 }
342                 #endregion
343
344                 #region Methods
345
346                 public override void Close ()
347                 {
348                         current = null;
349                         state = ReadState.Closed;
350                 }
351
352                 public override string GetAttribute (int attributeIndex)
353                 {
354                         if (NodeType == XmlNodeType.XmlDeclaration) {
355                                 XmlDeclaration decl = current as XmlDeclaration;
356                                 if (attributeIndex == 0)
357                                         return decl.Version;
358                                 else if (attributeIndex == 1) {
359                                         if (decl.Encoding != String.Empty)
360                                                 return decl.Encoding;
361                                         else if (decl.Standalone != String.Empty)
362                                                 return decl.Standalone;
363                                 }
364                                 else if (attributeIndex == 2 &&
365                                                 decl.Encoding != String.Empty && decl.Standalone != null)
366                                         return decl.Standalone;
367                                 throw new ArgumentOutOfRangeException ("Index out of range.");
368                         } else if (NodeType == XmlNodeType.DocumentType) {
369                                 XmlDocumentType doctype = current as XmlDocumentType;
370                                 if (attributeIndex == 0) {
371                                         if (doctype.PublicId != "")
372                                                 return doctype.PublicId;
373                                         else if (doctype.SystemId != "")
374                                                 return doctype.SystemId;
375                                 } else if (attributeIndex == 1)
376                                         if (doctype.PublicId == "" && doctype.SystemId != "")
377                                                 return doctype.SystemId;
378                                 throw new ArgumentOutOfRangeException ("Index out of range.");
379                         }
380
381                         // This is MS.NET bug which returns attributes in spite of EndElement.
382                         if (isEndElement || current == null)
383                                 return null;
384
385                         if (attributeIndex < 0 || attributeIndex > AttributeCount)
386                                 throw new ArgumentOutOfRangeException ("Index out of range.");
387
388                         return ownerLinkedNode.Attributes [attributeIndex].Value;
389                 }
390
391                 public override string GetAttribute (string name)
392                 {
393                         // This is MS.NET bug which returns attributes in spite of EndElement.
394                         if (isEndElement || current == null)
395                                 return null;
396
397                         if (NodeType == XmlNodeType.XmlDeclaration)
398                                 return GetXmlDeclarationAttribute (name);
399                         else if (NodeType == XmlNodeType.DocumentType)
400                                 return GetDocumentTypeAttribute (name);
401
402                         if (ownerLinkedNode.Attributes == null)
403                                 return null;
404                         XmlAttribute attr = ownerLinkedNode.Attributes [name];
405                         if (attr == null)
406                                 return null;
407                         else
408                                 return attr.Value;
409                 }
410
411                 public override string GetAttribute (string name, string namespaceURI)
412                 {
413                         // This is MS.NET bug which returns attributes in spite of EndElement.
414                         if (isEndElement || current == null)
415                                 return null;
416
417                         if (NodeType == XmlNodeType.XmlDeclaration)
418                                 return GetXmlDeclarationAttribute (name);
419                         else if (NodeType == XmlNodeType.DocumentType)
420                                 return GetDocumentTypeAttribute (name);
421
422                         if (ownerLinkedNode.Attributes == null)
423                                 return null;
424                         XmlAttribute attr = ownerLinkedNode.Attributes [name, namespaceURI];
425                         if (attr == null)
426                                 return null;    // In fact MS.NET returns null instead of String.Empty.
427                         else
428                                 return attr.Value;
429                 }
430
431                 private string GetXmlDeclarationAttribute (string name)
432                 {
433                         XmlDeclaration decl = current as XmlDeclaration;
434                         switch (name) {
435                         case "version":
436                                 return decl.Version;
437                         case "encoding":
438                                 // This is MS.NET bug that XmlNodeReturns in case of string.empty.
439                                 return decl.Encoding != String.Empty ? decl.Encoding : null;
440                         case "standalone":
441                                 return decl.Standalone;
442                         }
443                         return null;
444                 }
445
446                 private string GetDocumentTypeAttribute (string name)
447                 {
448                         XmlDocumentType doctype = current as XmlDocumentType;
449                         switch (name) {
450                         case "PUBLIC":
451                                 return doctype.PublicId;
452                         case "SYSTEM":
453                                 return doctype.SystemId;
454                         }
455                         return null;
456                 }
457
458                 XmlParserContext IHasXmlParserContext.ParserContext {
459                         get {
460                                 return new XmlParserContext (document.NameTable,
461                                         current == null ?
462                                                 new XmlNamespaceManager (document.NameTable) :
463                                                 current.ConstructNamespaceManager (),
464                                         document.DocumentType != null ? document.DocumentType.DTD : null,
465                                         current == null ? document.BaseURI : current.BaseURI,
466                                         XmlLang, XmlSpace, Encoding.Unicode);
467                         }
468                 }
469
470 #if NET_2_0
471                 public IDictionary<string, string> GetNamespacesInScope (XmlNamespaceScope scope)
472                 {
473                         IDictionary<string, string> table = new Dictionary<string, string> ();
474                         XmlNode n = current;
475                         do {
476                                 if (n.NodeType == XmlNodeType.Document)
477                                         break;
478                                 for (int i = 0; i < current.Attributes.Count; i++) {
479                                         XmlAttribute a = current.Attributes [i];
480                                         if (a.NamespaceURI == XmlNamespaceManager.XmlnsXmlns)
481                                                 table.Add (a.Prefix == XmlNamespaceManager.PrefixXmlns ? a.LocalName : String.Empty, a.Value);
482                                 }
483                                 if (scope == XmlNamespaceScope.Local)
484                                         return table;
485                                 n = n.ParentNode;
486                         } while (n != null);
487                         if (scope == XmlNamespaceScope.All)
488                                 table.Add (XmlNamespaceManager.PrefixXml, XmlNamespaceManager.XmlnsXml);
489                         return table;
490                 }
491 #endif
492
493                 private XmlElement GetCurrentElement ()
494                 {
495                         XmlElement el = null;
496                         switch (current.NodeType) {
497                         case XmlNodeType.Attribute:
498                                 el = ((XmlAttribute) current).OwnerElement;
499                                 break;
500                         case XmlNodeType.Element:
501                                 el = (XmlElement) current;
502                                 break;
503                         case XmlNodeType.Text:
504                         case XmlNodeType.CDATA:
505                         case XmlNodeType.EntityReference:
506                         case XmlNodeType.Comment:
507                         case XmlNodeType.SignificantWhitespace:
508                         case XmlNodeType.Whitespace:
509                         case XmlNodeType.ProcessingInstruction:
510                                 el = current.ParentNode as XmlElement;
511                                 break;
512                         }
513                         return el;
514                 }
515
516                 public override string LookupNamespace (string prefix)
517                 {
518                         if (current == null)
519                                 return null;
520
521                         XmlElement el = GetCurrentElement ();
522
523                         for (; el != null; el = el.ParentNode as XmlElement) {
524                                 for (int i = 0; i < el.Attributes.Count; i++) {
525                                         XmlAttribute attr = el.Attributes [i];
526                                         if (attr.NamespaceURI != XmlNamespaceManager.XmlnsXmlns)
527                                                 continue;
528                                         if (prefix == "") {
529                                                 if (attr.Prefix == "")
530                                                         return attr.Value;
531                                         }
532                                         else if (attr.LocalName == prefix)
533                                                 return attr.Value;
534                                         continue;
535                                 }
536                         }
537
538                         switch (prefix) {
539                         case XmlNamespaceManager.PrefixXml:
540                                 return XmlNamespaceManager.XmlnsXml;
541                         case XmlNamespaceManager.PrefixXmlns:
542                                 return XmlNamespaceManager.XmlnsXmlns;
543                         }
544                         return null;
545                 }
546
547 #if NET_2_0
548                 public string LookupPrefix (string ns)
549                 {
550                         return LookupPrefix (ns, false);
551                 }
552
553                 public string LookupPrefix (string ns, bool atomizedNames)
554                 {
555                         if (current == null)
556                                 return null;
557
558                         XmlElement el = GetCurrentElement ();
559
560                         for (; el != null; el = el.ParentNode as XmlElement) {
561                                 for (int i = 0; i < el.Attributes.Count; i++) {
562                                         XmlAttribute attr = el.Attributes [i];
563                                         if (atomizedNames) {
564                                                 if (!Object.ReferenceEquals (attr.NamespaceURI, XmlNamespaceManager.XmlnsXmlns))
565                                                         continue;
566                                                 if (Object.ReferenceEquals (attr.Value, ns))
567                                                         // xmlns:blah="..." -> LocalName, xmlns="..." -> String.Empty
568                                                         return attr.Prefix != String.Empty ? attr.LocalName : String.Empty;
569                                         } else {
570                                                 if (attr.NamespaceURI != XmlNamespaceManager.XmlnsXmlns)
571                                                         continue;
572                                                 if (attr.Value == ns)
573                                                         // xmlns:blah="..." -> LocalName, xmlns="..." -> String.Empty
574                                                         return attr.Prefix != String.Empty ? attr.LocalName : String.Empty;
575                                         }
576                                 }
577                         }
578                         switch (ns) {
579                         case XmlNamespaceManager.XmlnsXml:
580                                 return XmlNamespaceManager.PrefixXml;
581                         case XmlNamespaceManager.XmlnsXmlns:
582                                 return XmlNamespaceManager.PrefixXmlns;
583                         }
584                         return null;
585                 }
586 #endif
587
588                 public override void MoveToAttribute (int attributeIndex)
589                 {
590                         if (isEndElement || attributeIndex < 0 || attributeIndex > AttributeCount)
591                                 throw new ArgumentOutOfRangeException ();
592                         
593                         state = ReadState.Interactive;
594                         current = ownerLinkedNode.Attributes [attributeIndex];
595                 }
596
597                 public override bool MoveToAttribute (string name)
598                 {
599                         if (isEndElement || current == null)
600                                 return false;
601                         XmlNode tmpCurrent = current;
602                         if (current.ParentNode.NodeType == XmlNodeType.Attribute)
603                                 current = current.ParentNode;
604
605                         if (ownerLinkedNode.Attributes == null)
606                                 return false;
607                         XmlAttribute attr = ownerLinkedNode.Attributes [name];
608                         if (attr == null) {
609                                 current = tmpCurrent;
610                                 return false;
611                         }
612                         else {
613                                 current = attr;
614                                 return true;
615                         }
616                 }
617
618                 public override bool MoveToAttribute (string name, string namespaceURI)
619                 {
620                         if (isEndElement || current == null)
621                                 return false;
622
623                         if (ownerLinkedNode.Attributes == null)
624                                 return false;
625                         XmlAttribute attr = ownerLinkedNode.Attributes [name, namespaceURI];
626                         if (attr == null)
627                                 return false;
628                         else {
629                                 current = attr;
630                                 return true;
631                         }
632                 }
633
634                 public override bool MoveToElement ()
635                 {
636                         if (current == null)
637                                 return false;
638                         XmlNode n = ownerLinkedNode;
639                         if (current != n) {
640                                 current = n;
641                                 return true;
642                         } else 
643                                 return false;
644                 }
645
646                 public override bool MoveToFirstAttribute ()
647                 {
648                         if (current == null)
649                                 return false;
650
651                         if (ownerLinkedNode.Attributes == null)
652                                 return false;
653                         if(ownerLinkedNode.Attributes.Count > 0)
654                         {
655                                 current = ownerLinkedNode.Attributes [0];
656                                 return true;
657                         }
658                         else
659                                 return false;
660                 }
661
662                 public override bool MoveToNextAttribute ()
663                 {
664                         if (current == null)
665                                 return false;
666
667                         XmlNode anode = current;
668                         if (current.NodeType != XmlNodeType.Attribute) {
669                                 // then it's either an attribute child or anything on the tree.
670                                 if (current.ParentNode == null ||  // document, or non-tree node
671                                     current.ParentNode.NodeType != XmlNodeType.Attribute) // not an attr value
672                                         return MoveToFirstAttribute ();
673                                 anode = current.ParentNode;
674                         }
675
676                         {
677                                 XmlAttributeCollection ac = ((XmlAttribute) anode).OwnerElement.Attributes;
678                                 for (int i=0; i<ac.Count-1; i++)
679                                 {
680                                         XmlAttribute attr = ac [i];
681                                         if (attr == anode)
682                                         {
683                                                 i++;
684                                                 if (i == ac.Count)
685                                                         return false;
686                                                 current = ac [i];
687                                                 return true;
688                                         }
689                                 }
690                                 return false;
691                         }
692                 }
693
694                 public override bool Read ()
695                 {
696                         // FIXME: at some stage inlining might work effectively.
697                         // if (EOF)
698                         switch (state) {
699                         case ReadState.EndOfFile:
700                         case ReadState.Error:
701                         case ReadState.Closed:
702                                 return false;
703                         }
704
705 #if NET_2_0
706                         if (Binary != null)
707                                 Binary.Reset ();
708 #endif
709
710                         bool ret = ReadContent ();
711                         ownerLinkedNode = current;
712                         return ret;
713                 }
714
715                 bool ReadContent ()
716                 {
717                         if (ReadState == ReadState.Initial) {
718                                 current = startNode;
719                                 state = ReadState.Interactive;
720                                 // when startNode is document or fragment
721                                 if (ignoreStartNode)
722                                         current = startNode.FirstChild;
723                                 if (current == null) {
724                                         state = ReadState.Error;
725                                         return false;
726                                 } else
727                                         return true;
728                         }
729
730                         MoveToElement ();
731
732                         // don't step into EntityReference's children. Also
733                         // avoid re-entering children of already-consumed
734                         // element (i.e. when it is regarded as EndElement).
735                         XmlNode firstChild =
736                                 !isEndElement && current.NodeType != XmlNodeType.EntityReference ?
737                                 current.FirstChild : null;
738                         if (firstChild != null) {
739                                 isEndElement = false;
740                                 current = firstChild;
741                                 depth++;
742                                 return true;
743                         }
744
745                         if (current == startNode) { // Currently it is on the start node.
746                                 if (IsEmptyElement || isEndElement) {
747                                         // The start node is already consumed.
748                                         isEndElement = false;
749                                         current = null;
750                                         state = ReadState.EndOfFile;
751                                         return false;
752                                 } else {
753                                         // The start node is the only element
754                                         // which should be processed. Now it
755                                         // is set as EndElement.
756                                         isEndElement = true;
757                                         return true;
758                                 }
759                         }
760                         if (!isEndElement && !IsEmptyElement &&
761                             current.NodeType == XmlNodeType.Element) {
762                                 // element, currently not EndElement, and has
763                                 // no child. (such as <foo></foo>, which
764                                 // should become EndElement).
765                                 isEndElement = true;
766                                 return true;
767                         }
768
769                         // If NextSibling is available, move to there.
770                         XmlNode next = current.NextSibling;
771                         if (next != null) {
772                                 isEndElement = false;
773                                 current = next;
774                                 return true;
775                         }
776
777                         // Otherwise, parent.
778                         XmlNode parent = current.ParentNode;
779                         if (parent == null || parent == startNode && ignoreStartNode) {
780                                 // Parent is not available, or reached to
781                                 // the start node. This reader never sets 
782                                 // startNode as current if it was originally 
783                                 // ignored (e.g. startNode is XmlDocument).
784                                 isEndElement = false;
785                                 current = null;
786                                 state = ReadState.EndOfFile;
787                                 return false;
788                         } else {
789                                 // Parent was available, so return it as
790                                 // EndElement.
791                                 current = parent;
792                                 depth--;
793                                 isEndElement = true;
794                                 return true;
795                         }
796                 }
797
798                 public override bool ReadAttributeValue ()
799                 {
800                         if (current.NodeType == XmlNodeType.Attribute) {
801                                 if (current.FirstChild == null)
802                                         return false;
803                                 current = current.FirstChild;
804                                 return true;
805                         } else if (current.ParentNode.NodeType == XmlNodeType.Attribute) {
806                                 if (current.NextSibling == null)
807                                         return false;
808                                 current = current.NextSibling;
809                                 return true;
810                         } else
811                                 return false;
812                 }
813
814                 public override string ReadString ()
815                 {
816                         return base.ReadString ();
817                 }
818
819 #if !NET_2_1 || MONOTOUCH
820                 public override void ResolveEntity ()
821                 {
822                         throw new NotSupportedException ("Should not happen.");
823                 }
824 #endif
825
826                 public override void Skip ()
827                 {
828                         // Why is this overriden? Such skipping might raise
829                         // (or ignore) unexpected validation error.
830                         base.Skip ();
831                 }
832                 #endregion
833         }
834 }