2004-10-08 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.XML / Mono.Xml.XPath / XPathNavigatorReader.cs
1 //\r
2 // XPathNavigatorReader.cs\r
3 //\r
4 // Author:\r
5 //      Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>\r
6 //\r
7 // 2003 Atsushi Enomoto. No rights reserved.\r
8 // Copyright (C) 2004 Novell Inc.\r
9 \r
10 //\r
11 // Permission is hereby granted, free of charge, to any person obtaining\r
12 // a copy of this software and associated documentation files (the\r
13 // "Software"), to deal in the Software without restriction, including\r
14 // without limitation the rights to use, copy, modify, merge, publish,\r
15 // distribute, sublicense, and/or sell copies of the Software, and to\r
16 // permit persons to whom the Software is furnished to do so, subject to\r
17 // the following conditions:\r
18 // \r
19 // The above copyright notice and this permission notice shall be\r
20 // included in all copies or substantial portions of the Software.\r
21 // \r
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
29 //\r
30 using System;\r
31 using System.Text;\r
32 using System.Xml;\r
33 using System.Xml.Schema;\r
34 using System.Xml.XPath;\r
35 \r
36 namespace Mono.Xml.XPath\r
37 {\r
38 \r
39         internal class XPathNavigatorReader : XmlReader\r
40         {\r
41                 public XPathNavigatorReader (XPathNavigator nav)\r
42                 {\r
43                         // It seems that this class have only to support linked\r
44                         // node as its parameter\r
45                         switch (nav.NodeType) {\r
46                         case XPathNodeType.Attribute:\r
47                         case XPathNodeType.Namespace:\r
48                                 throw new InvalidOperationException (String.Format ("NodeType {0} is not supported to read as a subtree of an XPathNavigator.", nav.NodeType));\r
49                         }\r
50                         root = nav.Clone ();\r
51                         current = nav.Clone ();\r
52                 }\r
53 \r
54                 XPathNavigator root;\r
55                 XPathNavigator current;\r
56                 bool started;\r
57                 bool closed;\r
58                 bool endElement;\r
59                 bool attributeValueConsumed;\r
60                 StringBuilder readStringBuffer = new StringBuilder ();\r
61                 StringBuilder innerXmlBuilder = new StringBuilder ();\r
62 \r
63                 int depth = 0;\r
64                 int attributeCount = 0;\r
65                 bool eof;\r
66                 bool nextIsEOF;\r
67 \r
68                 #region Properties\r
69                 public override XmlNodeType NodeType \r
70                 {\r
71                         get {\r
72                                 if (ReadState != ReadState.Interactive)\r
73                                         return XmlNodeType.None;\r
74                                 if (endElement)\r
75                                         return XmlNodeType.EndElement;\r
76                                 if (attributeValueConsumed)\r
77                                         // Is there any way to get other kind of nodes than Text?\r
78                                         return XmlNodeType.Text;\r
79 \r
80                                 switch (current.NodeType) {\r
81                                 case XPathNodeType.Namespace:\r
82                                 case XPathNodeType.Attribute:\r
83                                         return XmlNodeType.Attribute;\r
84                                 case XPathNodeType.Comment:\r
85                                         return XmlNodeType.Comment;\r
86                                 case XPathNodeType.Element:\r
87                                         return XmlNodeType.Element;\r
88                                 case XPathNodeType.ProcessingInstruction:\r
89                                         return XmlNodeType.ProcessingInstruction;\r
90                                 case XPathNodeType.Root:\r
91                                         // It is actually Document, but in XmlReader there is no such situation to return Document.\r
92                                         return XmlNodeType.None;\r
93                                 case XPathNodeType.SignificantWhitespace:\r
94                                         return XmlNodeType.SignificantWhitespace;\r
95                                 case XPathNodeType.Text:\r
96                                         return XmlNodeType.Text;\r
97                                 case XPathNodeType.Whitespace:\r
98                                         return XmlNodeType.Whitespace;\r
99                                 default:\r
100                                         throw new InvalidOperationException (String.Format ("Current XPathNavigator status is {0} which is not acceptable to XmlReader.", current.NodeType));\r
101                                 }\r
102                         }\r
103                 }\r
104 \r
105                 public override string Name {\r
106                         get {\r
107                                 if (eof)\r
108                                         return String.Empty;\r
109                                 else if (current.NodeType == XPathNodeType.Namespace)\r
110                                         return current.Name == String.Empty ? "xmlns" : "xmlns:" + current.Name;\r
111                                 else\r
112                                         return current.Name;\r
113                         }\r
114                 }\r
115 \r
116                 public override string LocalName {\r
117                         get {\r
118                                 if (eof)\r
119                                         return String.Empty;\r
120                                 else if (current.NodeType == XPathNodeType.Namespace && current.LocalName == String.Empty)\r
121                                         return "xmlns";\r
122                                 else\r
123                                         return current.LocalName;\r
124                         }\r
125                 }\r
126 \r
127                 public override string NamespaceURI {\r
128                         get {\r
129                                 if (eof)\r
130                                         return String.Empty;\r
131                                 else if (current.NodeType == XPathNodeType.Namespace)\r
132                                         return XmlNamespaceManager.XmlnsXmlns;\r
133                                 else\r
134                                         return current.NamespaceURI;\r
135                         }\r
136                 }\r
137 \r
138                 public override string Prefix {\r
139                         get {\r
140                                 if (eof)\r
141                                         return String.Empty;\r
142                                 else if (current.NodeType == XPathNodeType.Namespace && current.LocalName != String.Empty)\r
143                                         return "xmlns";\r
144                                 else\r
145                                         return current.Prefix;\r
146                         }\r
147                 }\r
148 \r
149                 public override bool HasValue {\r
150                         get {\r
151                                 switch (current.NodeType) {\r
152                                 case XPathNodeType.Namespace:\r
153                                 case XPathNodeType.Attribute:\r
154                                 case XPathNodeType.Comment:\r
155                                 case XPathNodeType.ProcessingInstruction:\r
156                                 case XPathNodeType.SignificantWhitespace:\r
157                                 case XPathNodeType.Text:\r
158                                 case XPathNodeType.Whitespace:\r
159                                         return true;\r
160                                 }\r
161                                 return false;\r
162                         }\r
163                 }\r
164 \r
165                 public override int Depth {\r
166                         get {\r
167                                 switch (ReadState) {\r
168                                 case ReadState.EndOfFile:\r
169                                 case ReadState.Initial:\r
170                                 case ReadState.Closed:\r
171                                         return 0;\r
172                                 }\r
173                                 return depth;\r
174                         }\r
175                 }\r
176 \r
177                 public override string Value {\r
178                         get {\r
179                                 switch (current.NodeType) {\r
180                                 case XPathNodeType.Namespace:\r
181                                 case XPathNodeType.Attribute:\r
182                                 case XPathNodeType.Comment:\r
183                                 case XPathNodeType.ProcessingInstruction:\r
184                                 case XPathNodeType.SignificantWhitespace:\r
185                                 case XPathNodeType.Text:\r
186                                 case XPathNodeType.Whitespace:\r
187                                         return current.Value;\r
188                                 case XPathNodeType.Element:\r
189                                 case XPathNodeType.Root:\r
190                                         return String.Empty;\r
191                                 default:\r
192                                         throw new InvalidOperationException ("Current XPathNavigator status is {0} which is not acceptable to XmlReader.");\r
193                                 }\r
194                         }\r
195                 }\r
196 \r
197                 public override string BaseURI {\r
198                         get { return current.BaseURI; }\r
199                 }\r
200 \r
201                 public override bool IsEmptyElement {\r
202                         get { return current.IsEmptyElement; }\r
203                 }\r
204 \r
205                 public override bool IsDefault {\r
206                         get {\r
207                                 IXmlSchemaInfo si = current as IXmlSchemaInfo;\r
208                                 return si != null && si.IsDefault;\r
209                         }\r
210                 }\r
211 \r
212                 // It makes no sense.\r
213                 public override char QuoteChar {\r
214                         get { return '\"'; }\r
215                 }\r
216 \r
217                 public override string XmlLang {\r
218                         get { return current.XmlLang; }\r
219                 }\r
220 \r
221                 // It is meaningless.\r
222                 public override XmlSpace XmlSpace {\r
223                         get { return XmlSpace.None; }\r
224                 }\r
225 \r
226                 public override int AttributeCount {\r
227                         get { return attributeCount; }\r
228                 }\r
229 \r
230                 private int GetAttributeCount ()\r
231                 {\r
232                         int count = 0;\r
233                         if (current.MoveToFirstAttribute ()) {\r
234                                 do {\r
235                                         count++;\r
236                                 } while (current.MoveToNextAttribute ());\r
237                                 current.MoveToParent ();\r
238                         }\r
239                         if (current.MoveToFirstNamespace (XPathNamespaceScope.Local)) {\r
240                                 do {\r
241                                         count++;\r
242                                 } while (current.MoveToNextNamespace (XPathNamespaceScope.Local));\r
243                                 current.MoveToParent ();\r
244                         }\r
245                         return count;\r
246                 }\r
247                 \r
248                 private bool MoveToAttributeNavigator (int i)\r
249                 {\r
250                         switch (current.NodeType) {\r
251                         case XPathNodeType.Namespace:\r
252                         case XPathNodeType.Attribute:\r
253                                 this.MoveToElement ();\r
254                                 goto case XPathNodeType.Element;\r
255                         case XPathNodeType.Element:\r
256                                 int count = 0;\r
257                                 if (MoveToFirstAttribute ()) {\r
258                                         if (i == 0)\r
259                                                 return true;\r
260                                 }\r
261                                 for (count++; this.MoveToNextAttribute (); count++) {\r
262                                         if (count == i)\r
263                                                 return true;\r
264                                 }\r
265                                 break;\r
266                         }\r
267                         return false;\r
268                 }\r
269 \r
270                 public override string this [int i] {\r
271                         get {\r
272                                 XPathNavigator backup = current.Clone ();\r
273                                 try {\r
274                                         if (MoveToAttributeNavigator (i))\r
275                                                 return Value;\r
276                                         else\r
277                                                 throw new ArgumentOutOfRangeException ();\r
278                                 } finally {\r
279                                         current.MoveTo (backup);\r
280                                 }\r
281                         }\r
282                 }\r
283 \r
284                 private void SplitName (string name, out string localName, out string ns)\r
285                 {\r
286                         localName = name;\r
287                         ns = String.Empty;\r
288                         int colon = name.IndexOf (':');\r
289                         if (colon > 0) {\r
290                                 localName = name.Substring (colon + 1, name.Length - colon - 1);\r
291                                 ns = this.LookupNamespace (name.Substring (0, colon));\r
292                         }\r
293                 }\r
294 \r
295                 public override string this [string name] {\r
296                         get {\r
297                                 string localName;\r
298                                 string ns;\r
299                                 SplitName (name, out localName, out ns);\r
300                                 return this [localName, ns];\r
301                         }\r
302                 }\r
303 \r
304                 public override string this [string localName, string namespaceURI] {\r
305                         get {\r
306                                 string v = current.GetAttribute (localName, namespaceURI);\r
307                                 if (v != String.Empty)\r
308                                         return v;\r
309                                 XPathNavigator tmp = current.Clone ();\r
310                                 return tmp.MoveToAttribute (localName, namespaceURI) ? String.Empty : null;\r
311                         }\r
312                 }\r
313 \r
314                 public override bool EOF {\r
315                         get { return ReadState == ReadState.EndOfFile; }\r
316                 }\r
317 \r
318                 public override ReadState ReadState {\r
319                         get {\r
320                                 if (eof)\r
321                                         return ReadState.EndOfFile;\r
322                                 if (closed)\r
323                                         return ReadState.Closed;\r
324                                 else if (!started)\r
325                                         return ReadState.Initial;\r
326                                 return ReadState.Interactive;\r
327                         }\r
328                 }\r
329 \r
330                 public override XmlNameTable NameTable {\r
331                         get { return current.NameTable; }\r
332                 }\r
333                 #endregion\r
334 \r
335                 #region Methods\r
336 \r
337                 public override string GetAttribute (string name)\r
338                 {\r
339                         string localName;\r
340                         string ns;\r
341                         SplitName (name, out localName, out ns);\r
342                         return this [localName, ns];\r
343                 }\r
344 \r
345                 public override string GetAttribute (string localName, string namespaceURI)\r
346                 {\r
347                         return this [localName, namespaceURI];\r
348                 }\r
349 \r
350                 public override string GetAttribute (int i)\r
351                 {\r
352                         return this [i];\r
353                 }\r
354 \r
355                 private bool CheckAttributeMove (bool b)\r
356                 {\r
357                         if (b)\r
358                                 attributeValueConsumed = false;\r
359                         return b;\r
360                 }\r
361 \r
362                 public override bool MoveToAttribute (string name)\r
363                 {\r
364                         string localName;\r
365                         string ns;\r
366                         SplitName (name, out localName, out ns);\r
367                         return CheckAttributeMove (MoveToAttribute (localName, ns));\r
368                 }\r
369 \r
370                 public override bool MoveToAttribute (string localName, string namespaceURI)\r
371                 {\r
372                         XPathNavigator backup = null;\r
373                         switch (current.NodeType) {\r
374                         case XPathNodeType.Attribute:\r
375                                 backup = current.Clone ();\r
376                                 this.MoveToElement ();\r
377                                 goto case XPathNodeType.Element;\r
378                         case XPathNodeType.Element:\r
379                                 while (MoveToNextAttribute ())\r
380                                         if (current.LocalName == localName && current.NamespaceURI == namespaceURI) {\r
381                                                 attributeValueConsumed = false;\r
382                                                 return true;\r
383                                         }\r
384                                 break;\r
385                         }\r
386                         if (backup != null)\r
387                                 current = backup;\r
388                         return false;\r
389                 }\r
390 \r
391                 public override void MoveToAttribute (int i)\r
392                 {\r
393                         if (!MoveToAttributeNavigator (i))\r
394                                 throw new ArgumentOutOfRangeException ();\r
395                 }\r
396 \r
397                 public override bool MoveToFirstAttribute ()\r
398                 {\r
399                         bool b = CheckAttributeMove (current.MoveToFirstNamespace (XPathNamespaceScope.Local));\r
400                         if (b)\r
401                                 return true;\r
402                         return CheckAttributeMove (current.MoveToFirstAttribute ());\r
403                 }\r
404 \r
405                 public override bool MoveToNextAttribute ()\r
406                 {\r
407                         if (current.NodeType == XPathNodeType.Namespace) {\r
408                                 bool b = CheckAttributeMove (current.MoveToNextNamespace (XPathNamespaceScope.Local));\r
409                                 if (b)\r
410                                         return true;\r
411                                 current.MoveToParent ();\r
412                                 b = CheckAttributeMove (current.MoveToFirstAttribute ());\r
413                                 if (b)\r
414                                         return true;\r
415                         }\r
416                         return CheckAttributeMove (current.MoveToNextAttribute ());\r
417                 }\r
418 \r
419                 public override bool MoveToElement ()\r
420                 {\r
421                         if (current.NodeType == XPathNodeType.Attribute ||\r
422                                 current.NodeType == XPathNodeType.Namespace) {\r
423                                 attributeValueConsumed = false;\r
424                                 return current.MoveToParent ();\r
425                         }\r
426                         return false;\r
427                 }\r
428 \r
429                 public override void Close ()\r
430                 {\r
431                         closed = true;\r
432                         eof = true;\r
433                 }\r
434 \r
435                 public override bool Read ()\r
436                 {\r
437                         switch (ReadState) {\r
438                         case ReadState.EndOfFile:\r
439                         case ReadState.Closed:\r
440                         case ReadState.Error:\r
441                                 return false;\r
442                         case ReadState.Initial:\r
443                                 started = true;\r
444                                 switch (current.NodeType) {\r
445                                 case XPathNodeType.Root:\r
446                                         // recurse, but as Interactive\r
447                                         return Read ();\r
448                                 case XPathNodeType.Element:\r
449                                         if (current.IsEmptyElement)\r
450                                                 nextIsEOF = true;\r
451                                         attributeCount = GetAttributeCount ();\r
452                                         return true;\r
453                                 default:\r
454                                         nextIsEOF = true;\r
455                                         return true;\r
456                                 }\r
457                                 break;\r
458                         }\r
459 \r
460                         if (nextIsEOF) {\r
461                                 nextIsEOF = false;\r
462                                 eof = true;\r
463                                 return false;\r
464                         }\r
465 \r
466                         MoveToElement ();\r
467 \r
468                         if (endElement || !current.MoveToFirstChild ()) {\r
469                                 if (current.IsSamePosition (root)) {    // It should happen only when the root node was empty.\r
470                                         eof = true;\r
471                                         return false;\r
472                                 }\r
473                                 if (!current.MoveToNext ()) {\r
474                                         current.MoveToParent ();\r
475                                         depth--;\r
476                                         endElement = (current.NodeType == XPathNodeType.Element);\r
477                                         if (current.IsSamePosition (root)) {\r
478                                                 if (current.NodeType == XPathNodeType.Element)\r
479                                                         nextIsEOF = true;\r
480                                                 else {\r
481                                                         endElement = false;\r
482                                                         eof = true;\r
483                                                         return false;\r
484                                                 }\r
485                                         }\r
486                                 } else\r
487                                         endElement = false;\r
488                         }\r
489                         else if (!endElement)\r
490                                 depth++;\r
491                         attributeCount = GetAttributeCount ();\r
492                         return true;\r
493                 }\r
494 \r
495                 public override string ReadString ()\r
496                 {\r
497                         readStringBuffer.Length = 0;\r
498 \r
499                         switch (NodeType) {\r
500                         default:\r
501                                 return String.Empty;\r
502                         case XmlNodeType.Element:\r
503                                 if (IsEmptyElement)\r
504                                         return String.Empty;\r
505                                 do {\r
506                                         Read ();\r
507                                         switch (NodeType) {\r
508                                         case XmlNodeType.Text:\r
509                                         case XmlNodeType.CDATA:\r
510                                         case XmlNodeType.Whitespace:\r
511                                         case XmlNodeType.SignificantWhitespace:\r
512                                                 readStringBuffer.Append (Value);\r
513                                                 continue;\r
514                                         }\r
515                                         break;\r
516                                 } while (true);\r
517                                 break;\r
518                         case XmlNodeType.Text:\r
519                         case XmlNodeType.CDATA:\r
520                         case XmlNodeType.Whitespace:\r
521                         case XmlNodeType.SignificantWhitespace:\r
522                                 do {\r
523                                         switch (NodeType) {\r
524                                         case XmlNodeType.Text:\r
525                                         case XmlNodeType.CDATA:\r
526                                         case XmlNodeType.Whitespace:\r
527                                         case XmlNodeType.SignificantWhitespace:\r
528                                                 readStringBuffer.Append (Value);\r
529                                                 Read ();\r
530                                                 continue;\r
531                                         }\r
532                                         break;\r
533                                 } while (true);\r
534                                 break;\r
535                         }\r
536                         string ret = readStringBuffer.ToString ();\r
537                         readStringBuffer.Length = 0;\r
538                         return ret;\r
539                 }\r
540 \r
541 #if NET_1_1\r
542 #else\r
543                 public override string ReadInnerXml ()\r
544                 {\r
545                         if (ReadState != ReadState.Interactive)\r
546                                 return String.Empty;\r
547 \r
548                         switch (NodeType) {\r
549                         case XmlNodeType.Attribute:\r
550                                 return Value;\r
551                         case XmlNodeType.Element:\r
552                                 if (IsEmptyElement)\r
553                                         return String.Empty;\r
554 \r
555                                 int startDepth = Depth;\r
556 \r
557                                 innerXmlBuilder.Length = 0;\r
558                                 bool loop = true;\r
559                                 do {\r
560                                         Read ();\r
561                                         if (NodeType ==XmlNodeType.None)\r
562                                                 throw new InvalidOperationException ("unexpected end of xml.");\r
563                                         else if (NodeType == XmlNodeType.EndElement && Depth == startDepth) {\r
564                                                 loop = false;\r
565                                                 Read ();\r
566                                         }\r
567                                         else\r
568                                                 innerXmlBuilder.Append (GetCurrentTagMarkup ());\r
569                                 } while (loop);\r
570                                 string xml = innerXmlBuilder.ToString ();\r
571                                 innerXmlBuilder.Length = 0;\r
572                                 return xml;\r
573                         case XmlNodeType.None:\r
574                                 // MS document is incorrect. Seems not to progress.\r
575                                 return String.Empty;\r
576                         default:\r
577                                 Read ();\r
578                                 return String.Empty;\r
579                         }\r
580                 }\r
581                 \r
582                 StringBuilder atts = new StringBuilder ();\r
583                 private string GetCurrentTagMarkup ()\r
584                 {\r
585                         switch (NodeType) {\r
586                         case XmlNodeType.CDATA:\r
587                                 return String.Format ("<![CDATA[{0}]]>", Value.Replace ("]]>", "]]&gt;"));\r
588                         case XmlNodeType.Text:\r
589                                 return Value.Replace ("<", "&lt;");\r
590                         case XmlNodeType.Comment:\r
591                                 return String.Format ("<!--{0}-->", Value);\r
592                         case XmlNodeType.SignificantWhitespace:\r
593                         case XmlNodeType.Whitespace:\r
594                                 return Value;\r
595                         case XmlNodeType.EndElement:\r
596                                 return String.Format ("</{0}>", Name);\r
597                         }\r
598 \r
599                         bool isEmpty = IsEmptyElement;\r
600                         string name = Name;\r
601                         atts.Length = 0;\r
602                         XPathNavigator temp = current.Clone ();\r
603                         while (temp.MoveToNextAttribute ())\r
604                                 atts.AppendFormat (" {0}='{1}'", temp.Name, temp.Value.Replace ("'", "&apos;"));\r
605                         if (!IsEmptyElement)\r
606                                 return String.Format ("<{0}{1}>", name, atts);\r
607                         else\r
608                                 return String.Format ("<{0}{1} />", name, atts);\r
609                 }\r
610 \r
611                 // Arranged copy of XmlTextReader.ReadOuterXml()\r
612                 public override string ReadOuterXml ()\r
613                 {\r
614                         if (ReadState != ReadState.Interactive)\r
615                                 return String.Empty;\r
616 \r
617                         switch (NodeType) {\r
618                         case XmlNodeType.Attribute:\r
619                                 // strictly incompatible with MS... (it holds spaces attribute between name, value and "=" char (very trivial).\r
620                                 return String.Format ("{0}={1}{2}{1}", Name, QuoteChar, ReadInnerXml ());\r
621                         case XmlNodeType.Element:\r
622                                 bool isEmpty = IsEmptyElement;\r
623                                 string name = Name;\r
624                                 StringBuilder atts = new StringBuilder ();\r
625                                 XPathNavigator temp = current.Clone ();\r
626                                 while (temp.MoveToNextAttribute ())\r
627                                         atts.AppendFormat (" {0}='{1}'", temp.Name, temp.Value.Replace ("'", "&apos;"));\r
628 \r
629                                 if (!isEmpty)\r
630                                         return String.Format ("{0}{1}</{2}>", GetCurrentTagMarkup (), atts, ReadInnerXml (), name);\r
631                                 else\r
632                                         return String.Format ("{0}", GetCurrentTagMarkup ());\r
633                         case XmlNodeType.None:\r
634                                 // MS document is incorrect. Seems not to progress.\r
635                                 return String.Empty;\r
636                         default:\r
637                                 Read ();\r
638                                 return String.Empty;\r
639                         }\r
640                 }\r
641 #endif\r
642 \r
643                 public override string LookupNamespace (string prefix)\r
644                 {\r
645                         XPathNavigator backup = current.Clone ();\r
646                         try {\r
647                                 this.MoveToElement ();\r
648                                 if (current.MoveToFirstNamespace ()) {\r
649                                         do {\r
650                                                 if (current.LocalName == prefix)\r
651                                                         return current.Value;\r
652                                         } while (current.MoveToNextNamespace ());\r
653                                 }\r
654                                 return null;\r
655                         } finally {\r
656                                 current = backup;\r
657                         }\r
658                 }\r
659 \r
660                 // It does not support entity resolution.\r
661                 public override void ResolveEntity ()\r
662                 {\r
663                         throw new InvalidOperationException ();\r
664                 }\r
665 \r
666                 public override bool ReadAttributeValue () {\r
667                         if (NodeType != XmlNodeType.Attribute)\r
668                                 return false;\r
669                         if (attributeValueConsumed)\r
670                                 return false;\r
671                         attributeValueConsumed = true;\r
672                         return true;\r
673                 }\r
674                 #endregion\r
675         }\r
676 }\r