BindingFlags.Public needed here as Exception.HResult is now public in .NET 4.5. This...
[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 #if NET_2_0\r
31 \r
32 using System;\r
33 using System.Text;\r
34 using System.Xml;\r
35 using System.Xml.Schema;\r
36 using System.Xml.XPath;\r
37 \r
38 namespace Mono.Xml.XPath\r
39 {\r
40 \r
41         internal class XPathNavigatorReader : XmlReader\r
42         {\r
43                 public XPathNavigatorReader (XPathNavigator nav)\r
44                 {\r
45                         current = nav.Clone ();\r
46                 }\r
47 \r
48                 XPathNavigator root;\r
49                 XPathNavigator current;\r
50                 bool started;\r
51                 bool closed;\r
52                 bool endElement;\r
53                 bool attributeValueConsumed;\r
54                 StringBuilder readStringBuffer = new StringBuilder ();\r
55 #if NET_2_0\r
56                 StringBuilder innerXmlBuilder = new StringBuilder ();\r
57 #endif\r
58 \r
59                 int depth = 0;\r
60                 int attributeCount = 0;\r
61                 bool eof;\r
62 \r
63                 #region Properties\r
64 \r
65 #if NET_2_0\r
66                 public override bool CanReadBinaryContent {\r
67                         get { return true; }\r
68                 }\r
69 \r
70                 public override bool CanReadValueChunk {\r
71                         get { return true; }\r
72                 }\r
73 #endif\r
74 \r
75                 public override XmlNodeType NodeType {\r
76                         get {\r
77                                 if (ReadState != ReadState.Interactive)\r
78                                         return XmlNodeType.None;\r
79                                 if (endElement)\r
80                                         return XmlNodeType.EndElement;\r
81                                 if (attributeValueConsumed)\r
82                                         // Is there any way to get other kind of nodes than Text?\r
83                                         return XmlNodeType.Text;\r
84 \r
85                                 switch (current.NodeType) {\r
86                                 case XPathNodeType.Namespace:\r
87                                 case XPathNodeType.Attribute:\r
88                                         return XmlNodeType.Attribute;\r
89                                 case XPathNodeType.Comment:\r
90                                         return XmlNodeType.Comment;\r
91                                 case XPathNodeType.Element:\r
92                                         return XmlNodeType.Element;\r
93                                 case XPathNodeType.ProcessingInstruction:\r
94                                         return XmlNodeType.ProcessingInstruction;\r
95                                 case XPathNodeType.Root:\r
96                                         // It is actually Document, but in XmlReader there is no such situation to return Document.\r
97                                         return XmlNodeType.None;\r
98                                 case XPathNodeType.SignificantWhitespace:\r
99                                         return XmlNodeType.SignificantWhitespace;\r
100                                 case XPathNodeType.Text:\r
101                                         return XmlNodeType.Text;\r
102                                 case XPathNodeType.Whitespace:\r
103                                         return XmlNodeType.Whitespace;\r
104                                 default:\r
105                                         throw new InvalidOperationException (String.Format ("Current XPathNavigator status is {0} which is not acceptable to XmlReader.", current.NodeType));\r
106                                 }\r
107                         }\r
108                 }\r
109 \r
110                 public override string Name {\r
111                         get {\r
112                                 if (ReadState != ReadState.Interactive)\r
113                                         return String.Empty;\r
114                                 if (attributeValueConsumed)\r
115                                         return String.Empty;\r
116                                 else if (current.NodeType == XPathNodeType.Namespace)\r
117                                         return current.Name == String.Empty ? "xmlns" : "xmlns:" + current.Name;\r
118                                 else\r
119                                         return current.Name;\r
120                         }\r
121                 }\r
122 \r
123                 public override string LocalName {\r
124                         get {\r
125                                 if (ReadState != ReadState.Interactive)\r
126                                         return String.Empty;\r
127                                 if (attributeValueConsumed)\r
128                                         return String.Empty;\r
129                                 else if (current.NodeType == XPathNodeType.Namespace && current.LocalName == String.Empty)\r
130                                         return "xmlns";\r
131                                 else\r
132                                         return current.LocalName;\r
133                         }\r
134                 }\r
135 \r
136                 public override string NamespaceURI {\r
137                         get {\r
138                                 if (ReadState != ReadState.Interactive)\r
139                                         return String.Empty;\r
140                                 if (attributeValueConsumed)\r
141                                         return String.Empty;\r
142                                 else if (current.NodeType == XPathNodeType.Namespace)\r
143                                         return "http://www.w3.org/2000/xmlns/";\r
144                                 else\r
145                                         return current.NamespaceURI;\r
146                         }\r
147                 }\r
148 \r
149                 public override string Prefix {\r
150                         get {\r
151                                 if (ReadState != ReadState.Interactive)\r
152                                         return String.Empty;\r
153                                 if (attributeValueConsumed)\r
154                                         return String.Empty;\r
155                                 else if (current.NodeType == XPathNodeType.Namespace && current.LocalName != String.Empty)\r
156                                         return "xmlns";\r
157                                 else\r
158                                         return current.Prefix;\r
159                         }\r
160                 }\r
161 \r
162                 public override bool HasValue {\r
163                         get {\r
164                                 switch (current.NodeType) {\r
165                                 case XPathNodeType.Namespace:\r
166                                 case XPathNodeType.Attribute:\r
167                                 case XPathNodeType.Comment:\r
168                                 case XPathNodeType.ProcessingInstruction:\r
169                                 case XPathNodeType.SignificantWhitespace:\r
170                                 case XPathNodeType.Text:\r
171                                 case XPathNodeType.Whitespace:\r
172                                         return true;\r
173                                 }\r
174                                 return false;\r
175                         }\r
176                 }\r
177 \r
178                 public override int Depth {\r
179                         get {\r
180                                 if (ReadState != ReadState.Interactive)\r
181                                         return 0;\r
182 \r
183                                 if (NodeType == XmlNodeType.Attribute)\r
184                                         return depth + 1;\r
185                                 if (attributeValueConsumed)\r
186                                         return depth + 2;\r
187                                 return depth;\r
188                         }\r
189                 }\r
190 \r
191                 public override string Value {\r
192                         get {\r
193                                 if (ReadState != ReadState.Interactive)\r
194                                         return String.Empty;\r
195                                 switch (current.NodeType) {\r
196                                 case XPathNodeType.Namespace:\r
197                                 case XPathNodeType.Attribute:\r
198                                 case XPathNodeType.Comment:\r
199                                 case XPathNodeType.ProcessingInstruction:\r
200                                 case XPathNodeType.SignificantWhitespace:\r
201                                 case XPathNodeType.Text:\r
202                                 case XPathNodeType.Whitespace:\r
203                                         return current.Value;\r
204                                 case XPathNodeType.Element:\r
205                                 case XPathNodeType.Root:\r
206                                         return String.Empty;\r
207                                 default:\r
208                                         throw new InvalidOperationException ("Current XPathNavigator status is {0} which is not acceptable to XmlReader.");\r
209                                 }\r
210                         }\r
211                 }\r
212 \r
213                 public override string BaseURI {\r
214                         get { return current.BaseURI; }\r
215                 }\r
216 \r
217                 public override bool IsEmptyElement {\r
218                         get {\r
219                                 if (ReadState != ReadState.Interactive)\r
220                                         return false;\r
221                                 return current.IsEmptyElement;\r
222                         }\r
223                 }\r
224 \r
225                 public override bool IsDefault {\r
226                         get {\r
227 #if NET_2_0\r
228                                 IXmlSchemaInfo si = current as IXmlSchemaInfo;\r
229                                 return si != null && si.IsDefault;\r
230 #else\r
231                                 return false; // no way to check this.\r
232 #endif\r
233                         }\r
234                 }\r
235 \r
236                 // It makes no sense.\r
237                 public override char QuoteChar {\r
238                         get { return '\"'; }\r
239                 }\r
240 \r
241 #if NET_2_0\r
242                 public override IXmlSchemaInfo SchemaInfo {\r
243                         get { return current.SchemaInfo; }\r
244                 }\r
245 #endif\r
246 \r
247                 public override string XmlLang {\r
248                         get { return current.XmlLang; }\r
249                 }\r
250 \r
251                 // It is meaningless.\r
252                 public override XmlSpace XmlSpace {\r
253                         get { return XmlSpace.None; }\r
254                 }\r
255 \r
256                 public override int AttributeCount {\r
257                         get { return attributeCount; }\r
258                 }\r
259 \r
260                 private int GetAttributeCount ()\r
261                 {\r
262                         if (ReadState != ReadState.Interactive)\r
263                                 return 0;\r
264                         int count = 0;\r
265                         if (current.MoveToFirstAttribute ()) {\r
266                                 do {\r
267                                         count++;\r
268                                 } while (current.MoveToNextAttribute ());\r
269                                 current.MoveToParent ();\r
270                         }\r
271                         if (current.MoveToFirstNamespace (XPathNamespaceScope.Local)) {\r
272                                 do {\r
273                                         count++;\r
274                                 } while (current.MoveToNextNamespace (XPathNamespaceScope.Local));\r
275                                 current.MoveToParent ();\r
276                         }\r
277                         return count;\r
278                 }\r
279                 \r
280                 /*\r
281                 private bool MoveToAttributeNavigator (int i)\r
282                 {\r
283                         if (ReadState != ReadState.Interactive)\r
284                                 return false;\r
285                         switch (current.NodeType) {\r
286                         case XPathNodeType.Namespace:\r
287                         case XPathNodeType.Attribute:\r
288                                 this.MoveToElement ();\r
289                                 goto case XPathNodeType.Element;\r
290                         case XPathNodeType.Element:\r
291                                 int count = 0;\r
292                                 if (MoveToFirstAttribute ()) {\r
293                                         if (i == 0)\r
294                                                 return true;\r
295                                 }\r
296                                 for (count++; this.MoveToNextAttribute (); count++) {\r
297                                         if (count == i)\r
298                                                 return true;\r
299                                 }\r
300                                 break;\r
301                         }\r
302                         return false;\r
303                 }\r
304 \r
305                 public override string this [int i] {\r
306                         get {\r
307                                 XPathNavigator backup = current.Clone ();\r
308                                 try {\r
309                                         if (MoveToAttributeNavigator (i))\r
310                                                 return Value;\r
311                                         else\r
312                                                 throw new ArgumentOutOfRangeException ();\r
313                                 } finally {\r
314                                         current.MoveTo (backup);\r
315                                 }\r
316                         }\r
317                 }\r
318                 */\r
319 \r
320                 private void SplitName (string name, out string localName, out string ns)\r
321                 {\r
322                         if (name == "xmlns") {\r
323                                 localName = "xmlns";\r
324                                 ns = XmlNamespaceManager.XmlnsXmlns;\r
325                                 return;\r
326                         }\r
327                         localName = name;\r
328                         ns = String.Empty;\r
329                         int colon = name.IndexOf (':');\r
330                         if (colon > 0) {\r
331                                 localName = name.Substring (colon + 1, name.Length - colon - 1);\r
332                                 ns = this.LookupNamespace (name.Substring (0, colon));\r
333                                 if (name.Substring (0, colon) == "xmlns")\r
334                                         ns = XmlNamespaceManager.XmlnsXmlns;\r
335                         }\r
336                 }\r
337 \r
338                 public override string this [string name] {\r
339                         get {\r
340                                 string localName;\r
341                                 string ns;\r
342                                 SplitName (name, out localName, out ns);\r
343                                 return this [localName, ns];\r
344                         }\r
345                 }\r
346 \r
347                 public override string this [string localName, string namespaceURI] {\r
348                         get {\r
349                                 string v = current.GetAttribute (localName, namespaceURI);\r
350                                 if (v != String.Empty)\r
351                                         return v;\r
352                                 XPathNavigator tmp = current.Clone ();\r
353                                 return tmp.MoveToAttribute (localName, namespaceURI) ? String.Empty : null;\r
354                         }\r
355                 }\r
356 \r
357                 public override bool EOF {\r
358                         get { return ReadState == ReadState.EndOfFile; }\r
359                 }\r
360 \r
361                 public override ReadState ReadState {\r
362                         get {\r
363                                 if (eof)\r
364                                         return ReadState.EndOfFile;\r
365                                 if (closed)\r
366                                         return ReadState.Closed;\r
367                                 else if (!started)\r
368                                         return ReadState.Initial;\r
369                                 return ReadState.Interactive;\r
370                         }\r
371                 }\r
372 \r
373                 public override XmlNameTable NameTable {\r
374                         get { return current.NameTable; }\r
375                 }\r
376                 #endregion\r
377 \r
378                 #region Methods\r
379 \r
380                 public override string GetAttribute (string name)\r
381                 {\r
382                         string localName;\r
383                         string ns;\r
384                         SplitName (name, out localName, out ns);\r
385                         return this [localName, ns];\r
386                 }\r
387 \r
388                 public override string GetAttribute (string localName, string namespaceURI)\r
389                 {\r
390                         return this [localName, namespaceURI];\r
391                 }\r
392 \r
393                 public override string GetAttribute (int i)\r
394                 {\r
395                         return this [i];\r
396                 }\r
397 \r
398                 private bool CheckAttributeMove (bool b)\r
399                 {\r
400                         if (b)\r
401                                 attributeValueConsumed = false;\r
402                         return b;\r
403                 }\r
404 \r
405                 public override bool MoveToAttribute (string name)\r
406                 {\r
407                         string localName;\r
408                         string ns;\r
409                         SplitName (name, out localName, out ns);\r
410                         return MoveToAttribute (localName, ns);\r
411                 }\r
412 \r
413                 public override bool MoveToAttribute (string localName, string namespaceURI)\r
414                 {\r
415                         bool isNS = namespaceURI == "http://www.w3.org/2000/xmlns/";\r
416                         XPathNavigator backup = null;\r
417                         switch (current.NodeType) {\r
418                         case XPathNodeType.Namespace:\r
419                         case XPathNodeType.Attribute:\r
420                                 backup = current.Clone ();\r
421                                 this.MoveToElement ();\r
422                                 goto case XPathNodeType.Element;\r
423                         case XPathNodeType.Element:\r
424                                 if (MoveToFirstAttribute ()) {\r
425                                         do {\r
426                                                 bool match = false;\r
427                                                 if (isNS) {\r
428                                                         if (localName == "xmlns")\r
429                                                                 match = current.Name == String.Empty;\r
430                                                         else\r
431                                                                 match = localName == current.Name;\r
432                                                 }\r
433                                                 else\r
434                                                         match = current.LocalName == localName &&\r
435                                                                 current.NamespaceURI == namespaceURI;\r
436                                                 if (match) {\r
437                                                         attributeValueConsumed = false;\r
438                                                         return true;\r
439                                                 }\r
440                                         } while (MoveToNextAttribute ());\r
441                                         MoveToElement ();\r
442                                 }\r
443                                 break;\r
444                         }\r
445                         if (backup != null)\r
446                                 current = backup;\r
447                         return false;\r
448                 }\r
449 \r
450                 public override bool MoveToFirstAttribute ()\r
451                 {\r
452                         switch (current.NodeType) {\r
453                         case XPathNodeType.Element:\r
454                                 if (CheckAttributeMove (current.MoveToFirstNamespace (XPathNamespaceScope.Local)))\r
455                                         return true;\r
456                                 return CheckAttributeMove (current.MoveToFirstAttribute ());\r
457                         case XPathNodeType.Namespace:\r
458                         case XPathNodeType.Attribute:\r
459                                 current.MoveToParent ();\r
460                                 goto case XPathNodeType.Element;\r
461                         default:\r
462                                 return false;\r
463                         }\r
464                 }\r
465 \r
466                 public override bool MoveToNextAttribute ()\r
467                 {\r
468                         switch (current.NodeType) {\r
469                         case XPathNodeType.Element:\r
470                                 return MoveToFirstAttribute ();\r
471                         case XPathNodeType.Namespace:\r
472                                 if (CheckAttributeMove (current.MoveToNextNamespace (XPathNamespaceScope.Local)))\r
473                                         return true;\r
474                                 XPathNavigator bak = current.Clone ();\r
475                                 current.MoveToParent ();\r
476                                 if (CheckAttributeMove (current.MoveToFirstAttribute ()))\r
477                                         return true;\r
478                                 current.MoveTo (bak);\r
479                                 return false;\r
480                         case XPathNodeType.Attribute:\r
481                                 return CheckAttributeMove (current.MoveToNextAttribute ());\r
482                         default:\r
483                                 return false;\r
484                         }\r
485                 }\r
486 \r
487                 public override bool MoveToElement ()\r
488                 {\r
489                         if (current.NodeType == XPathNodeType.Attribute ||\r
490                                 current.NodeType == XPathNodeType.Namespace) {\r
491                                 attributeValueConsumed = false;\r
492                                 return current.MoveToParent ();\r
493                         }\r
494                         return false;\r
495                 }\r
496 \r
497                 public override void Close ()\r
498                 {\r
499                         closed = true;\r
500                         eof = true;\r
501                 }\r
502 \r
503                 public override bool Read ()\r
504                 {\r
505                         if (eof)\r
506                                 return false;\r
507 #if NET_2_0\r
508                         if (Binary != null)\r
509                                 Binary.Reset ();\r
510 #endif\r
511 \r
512                         switch (ReadState) {\r
513                         case ReadState.Interactive:\r
514                                 if ((IsEmptyElement || endElement) && root.IsSamePosition (current)) {\r
515                                         eof = true;\r
516                                         return false;\r
517                                 }\r
518                                 break;\r
519                         case ReadState.EndOfFile:\r
520                         case ReadState.Closed:\r
521                         case ReadState.Error:\r
522                                 return false;\r
523                         case ReadState.Initial:\r
524                                 started = true;\r
525                                 root = current.Clone ();\r
526                                 if (current.NodeType == XPathNodeType.Root &&\r
527                                         !current.MoveToFirstChild ()) {\r
528                                         endElement = false;\r
529                                         eof = true;\r
530                                         return false;\r
531                                 }\r
532                                 attributeCount = GetAttributeCount ();\r
533                                 return true;\r
534                         }\r
535 \r
536                         MoveToElement ();\r
537 \r
538                         if (endElement || !current.MoveToFirstChild ()) {\r
539                                 // EndElement of current element.\r
540                                 if (!endElement && !current.IsEmptyElement &&\r
541                                         current.NodeType == XPathNodeType.Element)\r
542                                         endElement = true;\r
543                                 else if (!current.MoveToNext ()) {\r
544                                         current.MoveToParent ();\r
545                                         if (current.NodeType == XPathNodeType.Root) {\r
546                                                 endElement = false;\r
547                                                 eof = true;\r
548                                                 return false;\r
549                                         }\r
550                                         endElement = (current.NodeType == XPathNodeType.Element);\r
551                                         if (endElement)\r
552                                                 depth--;\r
553                                 }\r
554                                 else\r
555                                         endElement = false;\r
556                         }\r
557                         else\r
558                                 depth++;\r
559 \r
560                         if (!endElement && current.NodeType == XPathNodeType.Element)\r
561                                 attributeCount = GetAttributeCount ();\r
562                         else\r
563                                 attributeCount = 0;\r
564 \r
565                         return true;\r
566                 }\r
567 \r
568                 public override string ReadString ()\r
569                 {\r
570                         readStringBuffer.Length = 0;\r
571 \r
572                         switch (NodeType) {\r
573                         default:\r
574                                 return String.Empty;\r
575                         case XmlNodeType.Element:\r
576                                 if (IsEmptyElement)\r
577                                         return String.Empty;\r
578                                 do {\r
579                                         Read ();\r
580                                         switch (NodeType) {\r
581                                         case XmlNodeType.Text:\r
582                                         case XmlNodeType.CDATA:\r
583                                         case XmlNodeType.Whitespace:\r
584                                         case XmlNodeType.SignificantWhitespace:\r
585                                                 readStringBuffer.Append (Value);\r
586                                                 continue;\r
587                                         }\r
588                                         break;\r
589                                 } while (true);\r
590                                 break;\r
591                         case XmlNodeType.Text:\r
592                         case XmlNodeType.CDATA:\r
593                         case XmlNodeType.Whitespace:\r
594                         case XmlNodeType.SignificantWhitespace:\r
595                                 do {\r
596                                         switch (NodeType) {\r
597                                         case XmlNodeType.Text:\r
598                                         case XmlNodeType.CDATA:\r
599                                         case XmlNodeType.Whitespace:\r
600                                         case XmlNodeType.SignificantWhitespace:\r
601                                                 readStringBuffer.Append (Value);\r
602                                                 Read ();\r
603                                                 continue;\r
604                                         }\r
605                                         break;\r
606                                 } while (true);\r
607                                 break;\r
608                         }\r
609                         string ret = readStringBuffer.ToString ();\r
610                         readStringBuffer.Length = 0;\r
611                         return ret;\r
612                 }\r
613 \r
614 #if NET_1_1\r
615 #else\r
616                 public override string ReadInnerXml ()\r
617                 {\r
618                         if (ReadState != ReadState.Interactive)\r
619                                 return String.Empty;\r
620 \r
621                         switch (NodeType) {\r
622                         case XmlNodeType.Attribute:\r
623                                 return Value;\r
624                         case XmlNodeType.Element:\r
625                                 if (IsEmptyElement)\r
626                                         return String.Empty;\r
627 \r
628                                 int startDepth = Depth;\r
629 \r
630                                 innerXmlBuilder.Length = 0;\r
631                                 bool loop = true;\r
632                                 do {\r
633                                         Read ();\r
634                                         if (NodeType ==XmlNodeType.None)\r
635                                                 throw new InvalidOperationException ("unexpected end of xml.");\r
636                                         else if (NodeType == XmlNodeType.EndElement && Depth == startDepth) {\r
637                                                 loop = false;\r
638                                                 Read ();\r
639                                         }\r
640                                         else\r
641                                                 innerXmlBuilder.Append (GetCurrentTagMarkup ());\r
642                                 } while (loop);\r
643                                 string xml = innerXmlBuilder.ToString ();\r
644                                 innerXmlBuilder.Length = 0;\r
645                                 return xml;\r
646                         case XmlNodeType.None:\r
647                                 // MS document is incorrect. Seems not to progress.\r
648                                 return String.Empty;\r
649                         default:\r
650                                 Read ();\r
651                                 return String.Empty;\r
652                         }\r
653                 }\r
654                 \r
655                 StringBuilder atts = new StringBuilder ();\r
656                 private string GetCurrentTagMarkup ()\r
657                 {\r
658                         switch (NodeType) {\r
659                         case XmlNodeType.CDATA:\r
660                                 return String.Format ("<![CDATA[{0}]]>", Value.Replace ("]]>", "]]&gt;"));\r
661                         case XmlNodeType.Text:\r
662                                 return Value.Replace ("<", "&lt;");\r
663                         case XmlNodeType.Comment:\r
664                                 return String.Format ("<!--{0}-->", Value);\r
665                         case XmlNodeType.SignificantWhitespace:\r
666                         case XmlNodeType.Whitespace:\r
667                                 return Value;\r
668                         case XmlNodeType.EndElement:\r
669                                 return String.Format ("</{0}>", Name);\r
670                         }\r
671 \r
672                         bool isEmpty = IsEmptyElement;\r
673                         string name = Name;\r
674                         atts.Length = 0;\r
675                         XPathNavigator temp = current.Clone ();\r
676                         while (temp.MoveToNextAttribute ())\r
677                                 atts.AppendFormat (" {0}='{1}'", temp.Name, temp.Value.Replace ("'", "&apos;"));\r
678                         if (!IsEmptyElement)\r
679                                 return String.Format ("<{0}{1}>", name, atts);\r
680                         else\r
681                                 return String.Format ("<{0}{1} />", name, atts);\r
682                 }\r
683 \r
684                 // Arranged copy of XmlTextReader.ReadOuterXml()\r
685                 public override string ReadOuterXml ()\r
686                 {\r
687                         if (ReadState != ReadState.Interactive)\r
688                                 return String.Empty;\r
689 \r
690                         switch (NodeType) {\r
691                         case XmlNodeType.Attribute:\r
692                                 // strictly incompatible with MS... (it holds spaces attribute between name, value and "=" char (very trivial).\r
693                                 return String.Format ("{0}={1}{2}{1}", Name, QuoteChar, ReadInnerXml ());\r
694                         case XmlNodeType.Element:\r
695                                 bool isEmpty = IsEmptyElement;\r
696                                 string name = Name;\r
697                                 StringBuilder atts = new StringBuilder ();\r
698                                 XPathNavigator temp = current.Clone ();\r
699                                 while (temp.MoveToNextAttribute ())\r
700                                         atts.AppendFormat (" {0}='{1}'", temp.Name, temp.Value.Replace ("'", "&apos;"));\r
701 \r
702                                 if (!isEmpty)\r
703                                         return String.Format ("{0}{1}</{2}>", GetCurrentTagMarkup (), atts, ReadInnerXml (), name);\r
704                                 else\r
705                                         return String.Format ("{0}", GetCurrentTagMarkup ());\r
706                         case XmlNodeType.None:\r
707                                 // MS document is incorrect. Seems not to progress.\r
708                                 return String.Empty;\r
709                         default:\r
710                                 Read ();\r
711                                 return String.Empty;\r
712                         }\r
713                 }\r
714 #endif\r
715 \r
716                 public override string LookupNamespace (string prefix)\r
717                 {\r
718                         XPathNavigator backup = current.Clone ();\r
719                         try {\r
720                                 this.MoveToElement ();\r
721                                 if (current.NodeType != XPathNodeType.Element) // text etc.\r
722                                         current.MoveToParent ();\r
723                                 if (current.MoveToFirstNamespace ()) {\r
724                                         do {\r
725                                                 if (current.LocalName == prefix)\r
726                                                         return current.Value;\r
727                                         } while (current.MoveToNextNamespace ());\r
728                                 }\r
729                                 return null;\r
730                         } finally {\r
731                                 current = backup;\r
732                         }\r
733                 }\r
734 \r
735                 // It does not support entity resolution.\r
736                 public override void ResolveEntity ()\r
737                 {\r
738                         throw new InvalidOperationException ();\r
739                 }\r
740 \r
741                 public override bool ReadAttributeValue () {\r
742                         if (NodeType != XmlNodeType.Attribute)\r
743                                 return false;\r
744                         if (attributeValueConsumed)\r
745                                 return false;\r
746                         attributeValueConsumed = true;\r
747                         return true;\r
748                 }\r
749                 #endregion\r
750         }\r
751 }\r
752 \r
753 #endif\r