Merge branch 'master' of github.com:mono/mono
[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 !MOONLIGHT
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 ?? startNode;
475                         do {
476                                 if (n.NodeType == XmlNodeType.Document)
477                                         break;
478                                 for (int i = 0; i < n.Attributes.Count; i++) {
479                                         XmlAttribute a = n.Attributes [i];
480                                         if (a.NamespaceURI == XmlNamespaceManager.XmlnsXmlns) {
481                                                 string key = a.Prefix == XmlNamespaceManager.PrefixXmlns ? a.LocalName : String.Empty;
482                                                 if (!table.ContainsKey (key))
483                                                         table.Add (key, a.Value);
484                                         }
485                                 }
486                                 if (scope == XmlNamespaceScope.Local)
487                                         return table;
488                                 n = n.ParentNode;
489                         } while (n != null);
490                         if (scope == XmlNamespaceScope.All)
491                                 table.Add (XmlNamespaceManager.PrefixXml, XmlNamespaceManager.XmlnsXml);
492                         return table;
493                 }
494 #endif
495
496                 private XmlElement GetCurrentElement ()
497                 {
498                         XmlElement el = null;
499                         switch (current.NodeType) {
500                         case XmlNodeType.Attribute:
501                                 el = ((XmlAttribute) current).OwnerElement;
502                                 break;
503                         case XmlNodeType.Element:
504                                 el = (XmlElement) current;
505                                 break;
506                         case XmlNodeType.Text:
507                         case XmlNodeType.CDATA:
508                         case XmlNodeType.EntityReference:
509                         case XmlNodeType.Comment:
510                         case XmlNodeType.SignificantWhitespace:
511                         case XmlNodeType.Whitespace:
512                         case XmlNodeType.ProcessingInstruction:
513                                 el = current.ParentNode as XmlElement;
514                                 break;
515                         }
516                         return el;
517                 }
518
519                 public override string LookupNamespace (string prefix)
520                 {
521                         if (current == null)
522                                 return null;
523
524                         XmlElement el = GetCurrentElement ();
525
526                         for (; el != null; el = el.ParentNode as XmlElement) {
527                                 for (int i = 0; i < el.Attributes.Count; i++) {
528                                         XmlAttribute attr = el.Attributes [i];
529                                         if (attr.NamespaceURI != XmlNamespaceManager.XmlnsXmlns)
530                                                 continue;
531                                         if (prefix == "") {
532                                                 if (attr.Prefix == "")
533                                                         return attr.Value;
534                                         }
535                                         else if (attr.LocalName == prefix)
536                                                 return attr.Value;
537                                         continue;
538                                 }
539                         }
540
541                         switch (prefix) {
542                         case XmlNamespaceManager.PrefixXml:
543                                 return XmlNamespaceManager.XmlnsXml;
544                         case XmlNamespaceManager.PrefixXmlns:
545                                 return XmlNamespaceManager.XmlnsXmlns;
546                         }
547                         return null;
548                 }
549
550 #if NET_2_0
551                 public string LookupPrefix (string ns)
552                 {
553                         return LookupPrefix (ns, false);
554                 }
555
556                 public string LookupPrefix (string ns, bool atomizedNames)
557                 {
558                         if (current == null)
559                                 return null;
560
561                         XmlElement el = GetCurrentElement ();
562
563                         for (; el != null; el = el.ParentNode as XmlElement) {
564                                 for (int i = 0; i < el.Attributes.Count; i++) {
565                                         XmlAttribute attr = el.Attributes [i];
566                                         if (atomizedNames) {
567                                                 if (!Object.ReferenceEquals (attr.NamespaceURI, XmlNamespaceManager.XmlnsXmlns))
568                                                         continue;
569                                                 if (Object.ReferenceEquals (attr.Value, ns))
570                                                         // xmlns:blah="..." -> LocalName, xmlns="..." -> String.Empty
571                                                         return attr.Prefix != String.Empty ? attr.LocalName : String.Empty;
572                                         } else {
573                                                 if (attr.NamespaceURI != XmlNamespaceManager.XmlnsXmlns)
574                                                         continue;
575                                                 if (attr.Value == ns)
576                                                         // xmlns:blah="..." -> LocalName, xmlns="..." -> String.Empty
577                                                         return attr.Prefix != String.Empty ? attr.LocalName : String.Empty;
578                                         }
579                                 }
580                         }
581                         switch (ns) {
582                         case XmlNamespaceManager.XmlnsXml:
583                                 return XmlNamespaceManager.PrefixXml;
584                         case XmlNamespaceManager.XmlnsXmlns:
585                                 return XmlNamespaceManager.PrefixXmlns;
586                         }
587                         return null;
588                 }
589 #endif
590
591                 public override void MoveToAttribute (int attributeIndex)
592                 {
593                         if (isEndElement || attributeIndex < 0 || attributeIndex > AttributeCount)
594                                 throw new ArgumentOutOfRangeException ();
595                         
596                         state = ReadState.Interactive;
597                         current = ownerLinkedNode.Attributes [attributeIndex];
598                 }
599
600                 public override bool MoveToAttribute (string name)
601                 {
602                         if (isEndElement || current == null)
603                                 return false;
604                         XmlNode tmpCurrent = current;
605                         if (current.ParentNode.NodeType == XmlNodeType.Attribute)
606                                 current = current.ParentNode;
607
608                         if (ownerLinkedNode.Attributes == null)
609                                 return false;
610                         XmlAttribute attr = ownerLinkedNode.Attributes [name];
611                         if (attr == null) {
612                                 current = tmpCurrent;
613                                 return false;
614                         }
615                         else {
616                                 current = attr;
617                                 return true;
618                         }
619                 }
620
621                 public override bool MoveToAttribute (string name, string namespaceURI)
622                 {
623                         if (isEndElement || current == null)
624                                 return false;
625
626                         if (ownerLinkedNode.Attributes == null)
627                                 return false;
628                         XmlAttribute attr = ownerLinkedNode.Attributes [name, namespaceURI];
629                         if (attr == null)
630                                 return false;
631                         else {
632                                 current = attr;
633                                 return true;
634                         }
635                 }
636
637                 public override bool MoveToElement ()
638                 {
639                         if (current == null)
640                                 return false;
641                         XmlNode n = ownerLinkedNode;
642                         if (current != n) {
643                                 current = n;
644                                 return true;
645                         } else 
646                                 return false;
647                 }
648
649                 public override bool MoveToFirstAttribute ()
650                 {
651                         if (current == null)
652                                 return false;
653
654                         if (ownerLinkedNode.Attributes == null)
655                                 return false;
656                         if(ownerLinkedNode.Attributes.Count > 0)
657                         {
658                                 current = ownerLinkedNode.Attributes [0];
659                                 return true;
660                         }
661                         else
662                                 return false;
663                 }
664
665                 public override bool MoveToNextAttribute ()
666                 {
667                         if (current == null)
668                                 return false;
669
670                         XmlNode anode = current;
671                         if (current.NodeType != XmlNodeType.Attribute) {
672                                 // then it's either an attribute child or anything on the tree.
673                                 if (current.ParentNode == null ||  // document, or non-tree node
674                                     current.ParentNode.NodeType != XmlNodeType.Attribute) // not an attr value
675                                         return MoveToFirstAttribute ();
676                                 anode = current.ParentNode;
677                         }
678
679                         {
680                                 XmlAttributeCollection ac = ((XmlAttribute) anode).OwnerElement.Attributes;
681                                 for (int i=0; i<ac.Count-1; i++)
682                                 {
683                                         XmlAttribute attr = ac [i];
684                                         if (attr == anode)
685                                         {
686                                                 i++;
687                                                 if (i == ac.Count)
688                                                         return false;
689                                                 current = ac [i];
690                                                 return true;
691                                         }
692                                 }
693                                 return false;
694                         }
695                 }
696
697                 public override bool Read ()
698                 {
699                         // FIXME: at some stage inlining might work effectively.
700                         // if (EOF)
701                         switch (state) {
702                         case ReadState.EndOfFile:
703                         case ReadState.Error:
704                         case ReadState.Closed:
705                                 return false;
706                         }
707
708 #if NET_2_0
709                         if (Binary != null)
710                                 Binary.Reset ();
711 #endif
712
713                         bool ret = ReadContent ();
714                         ownerLinkedNode = current;
715                         return ret;
716                 }
717
718                 bool ReadContent ()
719                 {
720                         if (ReadState == ReadState.Initial) {
721                                 current = startNode;
722                                 state = ReadState.Interactive;
723                                 // when startNode is document or fragment
724                                 if (ignoreStartNode)
725                                         current = startNode.FirstChild;
726                                 if (current == null) {
727                                         state = ReadState.Error;
728                                         return false;
729                                 } else
730                                         return true;
731                         }
732
733                         MoveToElement ();
734
735                         // don't step into EntityReference's children. Also
736                         // avoid re-entering children of already-consumed
737                         // element (i.e. when it is regarded as EndElement).
738                         XmlNode firstChild =
739                                 !isEndElement && current.NodeType != XmlNodeType.EntityReference ?
740                                 current.FirstChild : null;
741                         if (firstChild != null) {
742                                 isEndElement = false;
743                                 current = firstChild;
744                                 depth++;
745                                 return true;
746                         }
747
748                         if (current == startNode) { // Currently it is on the start node.
749                                 if (IsEmptyElement || isEndElement) {
750                                         // The start node is already consumed.
751                                         isEndElement = false;
752                                         current = null;
753                                         state = ReadState.EndOfFile;
754                                         return false;
755                                 } else {
756                                         // The start node is the only element
757                                         // which should be processed. Now it
758                                         // is set as EndElement.
759                                         isEndElement = true;
760                                         return true;
761                                 }
762                         }
763                         if (!isEndElement && !IsEmptyElement &&
764                             current.NodeType == XmlNodeType.Element) {
765                                 // element, currently not EndElement, and has
766                                 // no child. (such as <foo></foo>, which
767                                 // should become EndElement).
768                                 isEndElement = true;
769                                 return true;
770                         }
771
772                         // If NextSibling is available, move to there.
773                         XmlNode next = current.NextSibling;
774                         if (next != null) {
775                                 isEndElement = false;
776                                 current = next;
777                                 return true;
778                         }
779
780                         // Otherwise, parent.
781                         XmlNode parent = current.ParentNode;
782                         if (parent == null || parent == startNode && ignoreStartNode) {
783                                 // Parent is not available, or reached to
784                                 // the start node. This reader never sets 
785                                 // startNode as current if it was originally 
786                                 // ignored (e.g. startNode is XmlDocument).
787                                 isEndElement = false;
788                                 current = null;
789                                 state = ReadState.EndOfFile;
790                                 return false;
791                         } else {
792                                 // Parent was available, so return it as
793                                 // EndElement.
794                                 current = parent;
795                                 depth--;
796                                 isEndElement = true;
797                                 return true;
798                         }
799                 }
800
801                 public override bool ReadAttributeValue ()
802                 {
803                         if (current.NodeType == XmlNodeType.Attribute) {
804                                 if (current.FirstChild == null)
805                                         return false;
806                                 current = current.FirstChild;
807                                 return true;
808                         } else if (current.ParentNode.NodeType == XmlNodeType.Attribute) {
809                                 if (current.NextSibling == null)
810                                         return false;
811                                 current = current.NextSibling;
812                                 return true;
813                         } else
814                                 return false;
815                 }
816
817                 public override string ReadString ()
818                 {
819                         return base.ReadString ();
820                 }
821
822 #if !MOONLIGHT
823                 public override void ResolveEntity ()
824                 {
825                         throw new NotSupportedException ("Should not happen.");
826                 }
827 #endif
828
829                 public override void Skip ()
830                 {
831                         // Why is this overriden? Such skipping might raise
832                         // (or ignore) unexpected validation error.
833                         base.Skip ();
834                 }
835                 #endregion
836         }
837 }