2005-05-05 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.XML / Mono.Xml.XPath / XPathDocument2.cs
1 //\r
2 // Mono.Xml.XPath.XPathDocument2.cs\r
3 //\r
4 // Author:\r
5 //      Atsushi Enomoto <atsushi@ximian.com>\r
6 //\r
7 // (C)2004 Novell Inc.\r
8 //\r
9 // Another Document tree model.\r
10 //\r
11 \r
12 //\r
13 // Permission is hereby granted, free of charge, to any person obtaining\r
14 // a copy of this software and associated documentation files (the\r
15 // "Software"), to deal in the Software without restriction, including\r
16 // without limitation the rights to use, copy, modify, merge, publish,\r
17 // distribute, sublicense, and/or sell copies of the Software, and to\r
18 // permit persons to whom the Software is furnished to do so, subject to\r
19 // the following conditions:\r
20 // \r
21 // The above copyright notice and this permission notice shall be\r
22 // included in all copies or substantial portions of the Software.\r
23 // \r
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
31 //\r
32 #if NET_2_0\r
33 using System;\r
34 using System.Collections;\r
35 using System.Collections.Specialized;\r
36 using System.IO;\r
37 using System.Text;\r
38 using System.Xml;\r
39 using System.Xml.XPath;\r
40 \r
41 namespace Mono.Xml.XPath\r
42 {\r
43 \r
44 /*\r
45         public class Driver\r
46         {\r
47                 public static void Main ()\r
48                 {\r
49                         try {\r
50                                 DateTime start = DateTime.Now;\r
51                                 Console.WriteLine (DateTime.Now.Ticks);\r
52 #if false\r
53                                 XmlDocument doc = new XmlDocument ();\r
54                                 doc.PreserveWhitespace = true;\r
55                                 doc.Load (new XmlTextReader ("../TestResult.xml"));\r
56 #else\r
57                                 XPathDocument2 doc = new XPathDocument2 ();\r
58                                 doc.Load (new XmlTextReader ("../TestResult.xml"));\r
59 //                              XPathDocument doc = new XPathDocument ("../TestResult.xml", XmlSpace.Preserve);\r
60 //                              XPathDocument doc = new XPathDocument ("test.xml", XmlSpace.Preserve);\r
61 #endif\r
62 //                              doc.Load (new XmlTextReader ("test.xml"));\r
63 \r
64 //                              doc.WriteTo (new XmlTextWriter (Console.Out));\r
65 //return;\r
66                                 Console.WriteLine (DateTime.Now.Ticks);\r
67 \r
68                                 XPathNavigator nav = doc.CreateNavigator ();\r
69 //Console.WriteLine (nav.MoveToFirstChild ());\r
70 //Console.WriteLine (nav.LocalName + nav.NodeType);\r
71 //Console.WriteLine (nav.MoveToNext ());\r
72 //Console.WriteLine (nav.LocalName + nav.NodeType);\r
73 //Console.WriteLine (nav.MoveToNext ());\r
74 //Console.WriteLine (nav.LocalName + nav.NodeType);\r
75 //Console.WriteLine (nav.MoveToNext ());\r
76 //Console.WriteLine (nav.LocalName + nav.NodeType);\r
77 //nav.MoveToRoot ();\r
78 \r
79 \r
80                                 XmlReader reader = nav.ReadSubtree ();\r
81                                 XmlTextWriter w = new XmlTextWriter (new StringWriter ());\r
82 //                              XmlTextWriter w = new XmlTextWriter (Console.Out);\r
83                                 w.WriteNode (reader, false);\r
84                                 Console.WriteLine (DateTime.Now.Ticks);\r
85                                 Console.WriteLine (DateTime.Now.Ticks - start.Ticks);\r
86                         } catch (Exception ex) {\r
87                                 Console.WriteLine (ex);\r
88                         }\r
89                 }\r
90         }\r
91 */\r
92 \r
93         // Wrapper\r
94 \r
95         public class XPathDocument2 : IXPathNavigable\r
96         {\r
97                 XomRoot root;\r
98 \r
99                 public XPathDocument2 ()\r
100                         : this (new NameTable ())\r
101                 {\r
102                 }\r
103                 \r
104                 public XPathDocument2 (XmlNameTable nameTable)\r
105                 {\r
106                         root = new XomRoot (nameTable);\r
107                 }\r
108 \r
109                 public XmlNameTable NameTable {\r
110                         get { return root.NameTable; }\r
111                 }\r
112 \r
113                 public void LoadXml (string xml)\r
114                 {\r
115                         Load (new XmlTextReader (xml, XmlNodeType.Document, null));\r
116                 }\r
117 \r
118                 public void Load (TextReader reader)\r
119                 {\r
120                         Load (new XmlTextReader (reader));\r
121                 }\r
122 \r
123                 public void Load (XmlReader reader)\r
124                 {\r
125                         Load (reader, XmlSpace.None);\r
126                 }\r
127 \r
128                 public void Load (XmlReader reader, XmlSpace space)\r
129                 {\r
130                         root.Load (reader, space);\r
131                 }\r
132 \r
133                 public void Save (TextWriter writer)\r
134                 {\r
135                         XmlTextWriter xtw = new XmlTextWriter (writer);\r
136                         xtw.Formatting = Formatting.Indented;\r
137                         WriteTo (xtw);\r
138                 }\r
139 \r
140                 public void Save (XmlWriter writer)\r
141                 {\r
142                         WriteTo (writer);\r
143                 }\r
144 \r
145                 public void WriteTo (XmlWriter writer)\r
146                 {\r
147                         root.WriteTo (writer);\r
148                 }\r
149 \r
150                 public XPathNavigator CreateNavigator ()\r
151                 {\r
152                         return new XomNavigator (root);\r
153                 }\r
154         }\r
155 \r
156         // Xom part\r
157 \r
158         public struct XmlName\r
159         {\r
160                 public string Prefix;\r
161                 public string LocalName;\r
162                 public string Namespace;\r
163                 string fullName;\r
164 \r
165                 public XmlName (string prefix, string name, string ns)\r
166                 {\r
167                         this.Prefix = prefix == null ? "" : prefix;\r
168                         this.LocalName = name;\r
169                         this.Namespace = ns == null ? "" : ns;\r
170                         fullName = null;\r
171                 }\r
172 \r
173                 public override bool Equals (object o)\r
174                 {\r
175                         if ( !(o is XmlName))\r
176                                 return false;\r
177                         XmlName other = (XmlName) o;\r
178                         return LocalName == other.LocalName && Namespace == other.Namespace;\r
179                 }\r
180 \r
181                 public static bool operator == (XmlName n1, XmlName n2)\r
182                 {\r
183                         return n1.LocalName == n2.LocalName && n1.Namespace == n2.Namespace;\r
184                 }\r
185 \r
186                 public static bool operator != (XmlName n1, XmlName n2)\r
187                 {\r
188                         return n1.LocalName != n2.LocalName || n1.Namespace != n2.Namespace;\r
189                 }\r
190 \r
191                 public override int GetHashCode ()\r
192                 {\r
193                         if (fullName == null)\r
194                                 fullName = String.Concat (LocalName, "/", Namespace);\r
195                         return fullName.GetHashCode ();\r
196                 }\r
197 \r
198                 public override string ToString ()\r
199                 {\r
200                         if (fullName == null)\r
201                                 fullName = String.Concat (LocalName, "/", Namespace);\r
202                         return fullName;\r
203                 }\r
204         }\r
205 \r
206         public abstract class XomNode\r
207         {\r
208                 XomParentNode parent;\r
209                 string prefixedName;\r
210                 XomNode previousSibling;\r
211                 XomNode nextSibling;\r
212 \r
213                 public XomRoot Root {\r
214                         get {\r
215                                 XomNode n = this;\r
216                                 while (n.parent != null)\r
217                                         n = n.parent;\r
218                                 return (XomRoot) n;\r
219                         }\r
220                 }\r
221 \r
222                 public string PrefixedName {\r
223                         get {\r
224                                 if (prefixedName == null) {\r
225                                         if (Prefix.Length > 0)\r
226                                                 prefixedName = Prefix + ':' + LocalName;\r
227                                         else\r
228                                                 prefixedName = LocalName;\r
229                                 }\r
230                                 return prefixedName;\r
231                         }\r
232                 }\r
233 \r
234                 public virtual string BaseURI {\r
235                         get { return Root.BaseURI; }\r
236                 }\r
237 \r
238                 public virtual string XmlLang {\r
239                         get { return String.Empty; }\r
240                 }\r
241 \r
242                 public XomParentNode Parent {\r
243                         get { return parent; }\r
244                 }\r
245 \r
246                 public XomNode PreviousSibling {\r
247                         get { return previousSibling; }\r
248                 }\r
249 \r
250                 public XomNode NextSibling {\r
251                         get { return nextSibling; }\r
252                 }\r
253 \r
254                 internal void SetParent (XomParentNode parent)\r
255                 {\r
256                         this.parent = parent;\r
257                 }\r
258 \r
259                 internal void SetPreviousSibling (XomNode previous)\r
260                 {\r
261                         if (previous.parent != parent || this == previous)\r
262                                 throw new InvalidOperationException ();\r
263                         nextSibling = previous.nextSibling;\r
264                         previousSibling = previous;\r
265                         previous.nextSibling = this;\r
266                 }\r
267 \r
268                 internal void SetNextSibling (XomNode next)\r
269                 {\r
270                         if (next.parent != parent || this == next)\r
271                                 throw new InvalidOperationException ();\r
272                         previousSibling = next.previousSibling;\r
273                         nextSibling = next;\r
274                         next.previousSibling = this;\r
275                 }\r
276 \r
277                 internal void RemoveItself ()\r
278                 {\r
279                         if (previousSibling != null)\r
280                                 previousSibling.nextSibling = nextSibling;\r
281                         if (nextSibling != null)\r
282                                 nextSibling.previousSibling = previousSibling;\r
283                         parent = null;\r
284                 }\r
285 \r
286                 public string LookupPrefix (string ns)\r
287                 {\r
288                         XomElement n = this as XomElement;\r
289                         if (n == null)\r
290                                 n = Parent as XomElement;\r
291                         while (n != null) {\r
292                                 int len = n.NamespaceCount;\r
293                                 for (int i = 0; i < len; i++) {\r
294                                         XomNamespace nn = n.GetLocalNamespace (i);\r
295                                         if (nn.Value == ns)\r
296                                                 return nn.LocalName;\r
297                                 }\r
298                         }\r
299                         return null;\r
300                 }\r
301 \r
302                 public string LookupNamespace (string ns)\r
303                 {\r
304                         XomElement n = this as XomElement;\r
305                         if (n == null)\r
306                                 n = Parent as XomElement;\r
307                         while (n != null) {\r
308                                 int len = n.NamespaceCount;\r
309                                 for (int i = 0; i < len; i++) {\r
310                                         XomNamespace nn = n.GetLocalNamespace (i);\r
311                                         if (nn.Namespace== ns)\r
312                                                 return nn.Prefix;\r
313                                 }\r
314                         }\r
315                         return null;\r
316                 }\r
317 \r
318                 public virtual bool IsEmptyElement {\r
319                         get { return false; }\r
320                 }\r
321 \r
322                 public abstract string LocalName { get; }\r
323 \r
324                 public abstract string Namespace { get; }\r
325 \r
326                 public abstract string Prefix { get; }\r
327 \r
328                 public abstract string Value { get; set; }\r
329 \r
330                 public abstract XPathNodeType NodeType { get; }\r
331 \r
332                 public abstract int ChildCount { get; }\r
333 \r
334                 public virtual XomNode FirstChild { get { return null; } }\r
335 \r
336                 public virtual XomNode LastChild { get { return null; } }\r
337 \r
338                 internal abstract void BuildValue (StringBuilder sb);\r
339 \r
340                 public string OuterXml {\r
341                         get {\r
342                                 StringWriter sw = new StringWriter ();\r
343                                 XmlTextWriter xtw = new XmlTextWriter (sw);\r
344                                 WriteTo (xtw);\r
345                                 return sw.ToString ();\r
346                         }\r
347                 }\r
348 \r
349                 public string InnerXml {\r
350                         get {\r
351                                 StringWriter sw = new StringWriter ();\r
352                                 XmlTextWriter xtw = new XmlTextWriter (sw);\r
353                                 for (XomNode n = FirstChild; n != null; n = n.NextSibling)\r
354                                         n.WriteTo (xtw);\r
355                                 return sw.ToString ();\r
356                         }\r
357                 }\r
358 \r
359                 public abstract void WriteTo (XmlWriter writer);\r
360         }\r
361 \r
362         public interface IHasXomNode\r
363         {\r
364                 XomNode GetNode ();\r
365         }\r
366 \r
367         public abstract class XomParentNode : XomNode\r
368         {\r
369                 XomNode firstChild;\r
370                 XomNode lastChild;\r
371                 int childCount;\r
372 \r
373                 public void ReadNode (XmlReader reader, XmlSpace space)\r
374                 {\r
375                         switch (reader.ReadState) {\r
376                         case ReadState.Initial:\r
377                                 reader.Read ();\r
378                                 break;\r
379                         case ReadState.Error:\r
380                         case ReadState.Closed:\r
381                         case ReadState.EndOfFile:\r
382                                 throw new ArgumentException ("Argument XmlReader is not readable.");\r
383                         }\r
384 \r
385                         switch (reader.NodeType) {\r
386                         case XmlNodeType.Element:\r
387                                 XomElement el = new XomElement (reader.Prefix, reader.LocalName, reader.NamespaceURI, this);\r
388                                 if (reader.MoveToFirstAttribute ()) {\r
389                                         do {\r
390                                                 new XomAttribute (reader.Prefix, reader.LocalName, reader.NamespaceURI, reader.Value, el);\r
391                                         } while (reader.MoveToNextAttribute ());\r
392                                         reader.MoveToContent ();\r
393                                 }\r
394                                 if (reader.IsEmptyElement) {\r
395                                         el.SetIsEmpty (true);\r
396                                         reader.Read ();\r
397                                 }\r
398                                 else {\r
399                                         reader.Read ();\r
400                                         while (reader.NodeType != XmlNodeType.EndElement)\r
401                                                 el.ReadNode (reader, space);\r
402                                         reader.ReadEndElement ();\r
403                                 }\r
404                                 return;\r
405                         case XmlNodeType.Text:\r
406                         case XmlNodeType.CDATA:\r
407                                 XomText text = new XomText (reader.Value, this);\r
408                                 reader.Read ();\r
409                                 return;\r
410                         case XmlNodeType.SignificantWhitespace:\r
411                                 XomSignificantWhitespace sws = new XomSignificantWhitespace (reader.Value, this);\r
412                                 reader.Read ();\r
413                                 return;\r
414                         case XmlNodeType.Whitespace:\r
415                                 if (space == XmlSpace.Default) {\r
416                                         reader.Skip ();\r
417                                         return;\r
418                                 }\r
419                                 XomWhitespace ws = new XomWhitespace (reader.Value, this);\r
420                                 reader.Read ();\r
421                                 return;\r
422                         case XmlNodeType.ProcessingInstruction:\r
423                                 XomPI pi = new XomPI (reader.LocalName, reader.Value, this);\r
424                                 reader.Read ();\r
425                                 return;\r
426                         case XmlNodeType.Comment:\r
427                                 XomComment comment = new XomComment (reader.Value, this);\r
428                                 reader.Read ();\r
429                                 return;\r
430                         default:\r
431                                 reader.Skip ();\r
432                                 return;\r
433                         }\r
434                 }\r
435 \r
436                 public void AppendChild (XomNode child)\r
437                 {\r
438                         InsertBefore (child, null);\r
439                 }\r
440 \r
441                 public void InsertBefore (XomNode child, XomNode nextNode)\r
442                 {\r
443                         if (child.Parent != null)\r
444                                 throw new InvalidOperationException ("The child already has a parent.");\r
445                         if (nextNode == null) {\r
446                                 child.SetParent (this);\r
447                                 if (firstChild == null)\r
448                                         firstChild = lastChild = child;\r
449                                 else {\r
450                                         child.SetPreviousSibling (lastChild);\r
451                                         lastChild = child;\r
452                                 }\r
453                         } else {\r
454                                 if (nextNode.Parent != this)\r
455                                         throw new ArgumentException ("Argument nextNode is not a child of this node.");\r
456                                 child.SetNextSibling (nextNode);\r
457                         }\r
458                         childCount++;\r
459                 }\r
460 \r
461                 public abstract void Clear ();\r
462 \r
463                 public override XomNode FirstChild {\r
464                         get { return firstChild; }\r
465                 }\r
466 \r
467                 public override XomNode LastChild {\r
468                         get { return lastChild; }\r
469                 }\r
470 \r
471                 public override int ChildCount {\r
472                         get { return childCount; }\r
473                 }\r
474 \r
475                 internal void ClearChildren ()\r
476                 {\r
477                         firstChild = lastChild = null;\r
478                         childCount = 0;\r
479                 }\r
480 \r
481                 public void RemoveChild (XomNode child)\r
482                 {\r
483                         if (child == firstChild)\r
484                                 firstChild = child.NextSibling;\r
485                         if (child == lastChild)\r
486                                 lastChild = child.PreviousSibling;\r
487                         child.RemoveItself ();\r
488                         childCount--;\r
489                 }\r
490 \r
491                 public override string Value {\r
492                         get {\r
493                                 StringBuilder sb = new StringBuilder ();\r
494                                 BuildValue (sb);\r
495                                 return sb.ToString ();\r
496                         }\r
497                         set {\r
498                                 ClearChildren ();\r
499                                 AppendChild (new XomText (value));\r
500                         }\r
501                 }\r
502 \r
503                 internal override void BuildValue (StringBuilder sb)\r
504                 {\r
505                         for (XomNode n = FirstChild; n != null; n = n.NextSibling)\r
506                                 n.BuildValue (sb);\r
507                 }\r
508         }\r
509 \r
510         public class XomRoot : XomParentNode\r
511         {\r
512                 XmlNameTable nameTable;\r
513                 Hashtable identicalElements;\r
514                 string baseUri;\r
515 \r
516                 public XomRoot (XmlNameTable nameTable)\r
517                 {\r
518                         this.nameTable = nameTable;\r
519                         identicalElements = new Hashtable ();\r
520                 }\r
521 \r
522                 public override string BaseURI {\r
523                         get { return baseUri; }\r
524                 }\r
525 \r
526                 public void Load (XmlReader reader)\r
527                 {\r
528                         Load (reader, XmlSpace.None);\r
529                 }\r
530 \r
531                 public void Load (XmlReader reader, XmlSpace space)\r
532                 {\r
533                         baseUri = reader.BaseURI;\r
534                         while (!reader.EOF)\r
535                                 ReadNode (reader, space);\r
536                 }\r
537 \r
538                 public XmlNameTable NameTable {\r
539                         get { return nameTable; }\r
540                 }\r
541 \r
542                 public override string Prefix {\r
543                         get { return ""; }\r
544                 }\r
545 \r
546                 public override string LocalName {\r
547                         get { return ""; }\r
548                 }\r
549 \r
550                 public override string Namespace {\r
551                         get { return ""; }\r
552                 }\r
553 \r
554                 public override XPathNodeType NodeType {\r
555                         get { return XPathNodeType.Root; }\r
556                 }\r
557 \r
558                 public override void Clear ()\r
559                 {\r
560                         ClearChildren ();\r
561                 }\r
562 \r
563                 public override void WriteTo (XmlWriter writer)\r
564                 {\r
565                         for (XomNode n = FirstChild; n != null; n = n.NextSibling)\r
566                                 n.WriteTo (writer);\r
567                 }\r
568 \r
569                 public XomElement GetIdenticalNode (string id)\r
570                 {\r
571                         return identicalElements [id] as XomElement;\r
572                 }\r
573 \r
574                 internal void GetIdenticalNode (string id, XomElement element)\r
575                 {\r
576                         identicalElements.Add (id, element);\r
577                 }\r
578         }\r
579 \r
580         public class XomElement : XomParentNode\r
581         {\r
582                 XmlName qname;\r
583                 bool isEmptyElement;\r
584 \r
585                 ArrayList attributes;\r
586                 ArrayList namespaces;\r
587 \r
588                 public XomElement (string name)\r
589                         : this ("", name, "", null)\r
590                 {\r
591                 }\r
592 \r
593                 public XomElement (string name, XomRoot root)\r
594                         : this ("", name, "", root)\r
595                 {\r
596                 }\r
597 \r
598                 public XomElement (string name, string ns)\r
599                         : this ("", name, ns, null)\r
600                 {\r
601                 }\r
602 \r
603                 public XomElement (string name, string ns, XomRoot root)\r
604                         : this ("", name, ns, root)\r
605                 {\r
606                 }\r
607 \r
608                 public XomElement (string prefix, string name, string ns)\r
609                         : this (prefix, name, ns, null)\r
610                 {\r
611                 }\r
612 \r
613                 public XomElement (string prefix, string name, string ns, XomParentNode parent)\r
614                 {\r
615                         qname.LocalName = name;\r
616                         qname.Namespace = ns == null ? "" : ns;\r
617                         qname.Prefix = prefix == null ? "" : prefix;\r
618                         if (parent != null)\r
619                                 parent.AppendChild (this);\r
620                 }\r
621 \r
622                 public override bool IsEmptyElement {\r
623                         get { return isEmptyElement; }\r
624                 }\r
625 \r
626                 internal void SetIsEmpty (bool value)\r
627                 {\r
628                         isEmptyElement = value;\r
629                 }\r
630 \r
631                 public override string Prefix {\r
632                         get { return qname.Prefix; }\r
633                 }\r
634 \r
635                 public override string LocalName {\r
636                         get { return qname.LocalName; }\r
637                 }\r
638 \r
639                 public override string Namespace {\r
640                         get { return qname.Namespace; }\r
641                 }\r
642 \r
643                 public override XPathNodeType NodeType {\r
644                         get { return XPathNodeType.Element; }\r
645                 }\r
646 \r
647                 public override void Clear ()\r
648                 {\r
649                         if (attributes != null)\r
650                                 attributes.Clear ();\r
651                         if (namespaces != null)\r
652                                 namespaces.Clear ();\r
653                         ClearChildren ();\r
654                 }\r
655 \r
656                 public void AppendAttribute (XomAttribute attr)\r
657                 {\r
658                         if (attr.Parent != null)\r
659                                 throw new InvalidOperationException ("The argument attribute already have another element owner.");\r
660                         attr.SetParent (this);\r
661                         if (attributes == null)\r
662                                 attributes = new ArrayList ();\r
663                         attributes.Add (attr);\r
664                 }\r
665 \r
666 /*\r
667                 public void UpdateAttribute (XomAttribute attr)\r
668                 {\r
669                         if (attr.Parent != null)\r
670                                 throw new InvalidOperationException ("The argument attribute already have another element owner.");\r
671                         XomAttribute existing = GetAttribute (attr.LocalName, attr.Namespace);\r
672                         if (existing != null)\r
673                                 RemoveAttribute (existing);\r
674                         if (attributes == null)\r
675                                 attributes = new ArrayList ();\r
676                         attr.SetParent (this);\r
677                         attributes.Add (attr);\r
678                 }\r
679 */\r
680 \r
681                 public XomAttribute GetAttribute (int index)\r
682                 {\r
683                         return attributes == null ? null : attributes [index] as XomAttribute;\r
684                 }\r
685 \r
686                 public XomAttribute GetAttribute (string name, string ns)\r
687                 {\r
688                         if (attributes == null)\r
689                                 return null;\r
690                         for (int i = 0; i < attributes.Count; i++) {\r
691                                 XomAttribute a = attributes [i] as XomAttribute;\r
692                                 if (a.LocalName == name && a.Namespace == ns)\r
693                                         return a;\r
694                         }\r
695                         return null;\r
696                 }\r
697 \r
698                 public XomAttribute GetNextAttribute (XomAttribute attr)\r
699                 {\r
700                         if (attributes == null || attributes.Count == 0)\r
701                                 return null;\r
702                         if (attributes [attributes.Count - 1] == attr)\r
703                                 return null;\r
704                         // It is not efficient, but usually there won't be so many attributes in an element.\r
705                         int index = attributes.IndexOf (attr);\r
706                         if (index < 0)\r
707                                 return null;\r
708                         return attributes [index + 1] as XomAttribute;\r
709                 }\r
710 \r
711                 public int AttributeCount {\r
712                         get { return attributes == null ? 0 : attributes.Count; }\r
713                 }\r
714 \r
715                 public void RemoveAttribute (XomAttribute attr)\r
716                 {\r
717                         if (attributes == null)\r
718                                 return;\r
719                         attributes.Remove (attr);\r
720                         attr.SetParent (null);\r
721                 }\r
722 \r
723                 public void AppendNamespace (string prefix, string ns)\r
724                 {\r
725                         if (namespaces == null)\r
726                                 namespaces = new ArrayList ();\r
727                         namespaces.Add (new XomNamespace (prefix, ns));\r
728                 }\r
729 \r
730                 public XomNamespace GetLocalNamespace (int index)\r
731                 {\r
732                         if (namespaces == null || namespaces.Count <= index)\r
733                                 return null;\r
734                         return namespaces [index] as XomNamespace;\r
735                 }\r
736 \r
737                 public XomNamespace GetLocalNamespace (string prefix)\r
738                 {\r
739                         if (namespaces == null)\r
740                                 return null;\r
741                         for (int i = 0; i < namespaces.Count; i++) {\r
742                                 XomNamespace qname = namespaces [i] as XomNamespace;\r
743                                 if (qname.LocalName == prefix)\r
744                                         return qname;\r
745                         }\r
746                         return null;\r
747                 }\r
748 \r
749                 public XomNamespace GetNextLocalNamespace (XomNamespace n)\r
750                 {\r
751                         if (namespaces == null || namespaces.Count == 0)\r
752                                 return null;\r
753                         if (namespaces [namespaces.Count - 1] == n)\r
754                                 return null;\r
755                         // It is not efficient, but usually there won't be so many attributes in an element.\r
756                         int index = namespaces.IndexOf (n);\r
757                         if (index < 0)\r
758                                 return null;\r
759                         return namespaces [index + 1] as XomNamespace;\r
760                 }\r
761 \r
762                 public int NamespaceCount {\r
763                         get { return namespaces == null ? 0 : namespaces.Count; }\r
764                 }\r
765 \r
766                 public void RemoveNamespace (string prefix)\r
767                 {\r
768                         if (namespaces == null)\r
769                                 return;\r
770                         for (int i = 0; i < namespaces.Count; i++) {\r
771                                 XomNamespace qname = namespaces [i] as XomNamespace;\r
772                                 if (qname.LocalName == prefix) {\r
773                                         namespaces.RemoveAt (i);\r
774                                         return;\r
775                                 }\r
776                         }\r
777                 }\r
778 \r
779                 public override void WriteTo (XmlWriter writer)\r
780                 {\r
781                         writer.WriteStartElement (Prefix, LocalName, Namespace);\r
782                         if (namespaces != null) {\r
783                                 foreach (XomNamespace n in namespaces)\r
784                                         n.WriteTo (writer);\r
785                         }\r
786                         if (attributes != null) {\r
787                                 foreach (XomAttribute a in attributes)\r
788                                         a.WriteTo (writer);\r
789                         }\r
790 \r
791                         for (XomNode n = FirstChild; n != null; n = n.NextSibling)\r
792                                 n.WriteTo (writer);\r
793 \r
794                         writer.WriteEndElement ();\r
795                 }\r
796         }\r
797 \r
798         public class XomAttribute : XomNode\r
799         {\r
800                 XmlName qname;\r
801                 string value;\r
802 \r
803                 public XomAttribute (string name, string value)\r
804                         : this ("", name, "", value, null)\r
805                 {\r
806                 }\r
807 \r
808                 public XomAttribute (string name, string value, XomElement owner)\r
809                         : this ("", name, "", value, owner)\r
810                 {\r
811                 }\r
812 \r
813                 public XomAttribute (string name, string ns, string value)\r
814                         : this ("", name, ns, value, null)\r
815                 {\r
816                 }\r
817 \r
818                 public XomAttribute (string name, string ns, string value, XomElement owner)\r
819                         : this ("", name, ns, value, owner)\r
820                 {\r
821                 }\r
822 \r
823                 public XomAttribute (string prefix, string name, string ns, string value)\r
824                         : this ("", name, ns, value, null)\r
825                 {\r
826                 }\r
827 \r
828                 public XomAttribute (string prefix, string name, string ns, string value, XomElement owner)\r
829                 {\r
830                         qname.LocalName = name;\r
831                         qname.Namespace = ns;\r
832                         qname.Prefix = prefix;\r
833                         this.value = value;\r
834                         if (owner != null)\r
835                                 owner.AppendAttribute (this);\r
836                 }\r
837 \r
838                 public override string Prefix {\r
839                         get { return qname.Prefix; }\r
840                 }\r
841 \r
842                 public override string LocalName {\r
843                         get { return qname.LocalName; }\r
844                 }\r
845 \r
846                 public override string Namespace {\r
847                         get { return qname.Namespace; }\r
848                 }\r
849 \r
850                 public override XPathNodeType NodeType {\r
851                         get { return XPathNodeType.Attribute; }\r
852                 }\r
853 \r
854                 public override int ChildCount { get { return 0; } }\r
855 \r
856                 public override string Value {\r
857                         get { return value; }\r
858                         set { this.value = value; }\r
859                 }\r
860 \r
861                 internal override void BuildValue (StringBuilder sb)\r
862                 {\r
863                         sb.Append (value);\r
864                 }\r
865 \r
866                 public override void WriteTo (XmlWriter writer)\r
867                 {\r
868                         writer.WriteAttributeString (Prefix, LocalName, Namespace, Value);\r
869                 }\r
870         }\r
871 \r
872         public class XomNamespace : XomNode\r
873         {\r
874                 #region static members\r
875                 static XomNamespace xml;\r
876 \r
877                 static XomNamespace ()\r
878                 {\r
879                         xml = new XomNamespace ("xml", "http://www.w3.org/XML/1998/namespace");\r
880                 }\r
881 \r
882                 public static XomNamespace Xml {\r
883                         get { return xml; }\r
884                 }\r
885                 #endregion\r
886 \r
887                 XmlName qname;\r
888 \r
889                 public XomNamespace (string prefix, string ns)\r
890                 {\r
891                         qname.LocalName = prefix;\r
892                         qname.Namespace = ns;\r
893                 }\r
894 \r
895                 public override int ChildCount {\r
896                         get { return 0; }\r
897                 }\r
898 \r
899                 public override string LocalName {\r
900                         get { return qname.LocalName; }\r
901                 }\r
902 \r
903                 public override string Prefix {\r
904                         get { return LocalName; }\r
905                 }\r
906 \r
907                 public override string Namespace {\r
908                         get { return Value; }\r
909                 }\r
910 \r
911                 public override string Value {\r
912                         get { return qname.Namespace; }\r
913                         set { qname.Namespace = value; }\r
914                 }\r
915 \r
916                 public override XPathNodeType NodeType {\r
917                         get { return XPathNodeType.Namespace; }\r
918                 }\r
919 \r
920                 public override void WriteTo (XmlWriter writer)\r
921                 {\r
922                         if (LocalName != "")\r
923                                 writer.WriteAttributeString ("xmlns", LocalName, "http://www.w3.org/2000/xmlns/", Namespace);\r
924                         else\r
925                                 writer.WriteAttributeString ("", "xmlns", "http://www.w3.org/2000/xmlns/", Namespace);\r
926                 }\r
927 \r
928                 internal override void BuildValue (StringBuilder sb)\r
929                 {\r
930                         sb.Append (Value);\r
931                 }\r
932         }\r
933 \r
934         public class XomComment : XomNode\r
935         {\r
936                 string value;\r
937 \r
938                 public XomComment (string value)\r
939                         : this (value, null)\r
940                 {\r
941                 }\r
942 \r
943                 public XomComment (string value, XomParentNode parent)\r
944                 {\r
945                         this.value = value;\r
946                         if (parent != null)\r
947                                 parent.AppendChild (this);\r
948                 }\r
949 \r
950                 public override string Prefix {\r
951                         get { return ""; }\r
952                 }\r
953 \r
954                 public override string LocalName {\r
955                         get { return ""; }\r
956                 }\r
957 \r
958                 public override string Namespace {\r
959                         get { return ""; }\r
960                 }\r
961 \r
962                 public override XPathNodeType NodeType {\r
963                         get { return XPathNodeType.Comment; }\r
964                 }\r
965 \r
966                 public override string Value {\r
967                         get { return value; }\r
968                         set { this.value += value; }\r
969                 }\r
970 \r
971                 internal override void BuildValue (StringBuilder sb)\r
972                 {\r
973                         sb.Append (value);\r
974                 }\r
975 \r
976                 public override int ChildCount { get { return 0; } }\r
977 \r
978                 public override void WriteTo (XmlWriter writer)\r
979                 {\r
980                         writer.WriteComment (Value);\r
981                 }\r
982         }\r
983 \r
984         public class XomPI : XomNode\r
985         {\r
986                 string value;\r
987                 string name;\r
988 \r
989                 public XomPI (string name, string value)\r
990                         : this (name, value, null)\r
991                 {\r
992                 }\r
993 \r
994                 public XomPI (string name, string value, XomParentNode parent)\r
995                 {\r
996                         this.name = name;\r
997                         if (value == null)\r
998                                 value = "";\r
999                         this.value = value;\r
1000                         if (parent != null)\r
1001                                 parent.AppendChild (this);\r
1002                 }\r
1003 \r
1004                 public override string Prefix {\r
1005                         get { return ""; }\r
1006                 }\r
1007 \r
1008                 public override string LocalName {\r
1009                         get { return name; }\r
1010                 }\r
1011 \r
1012                 public override string Namespace {\r
1013                         get { return ""; }\r
1014                 }\r
1015 \r
1016                 public override XPathNodeType NodeType {\r
1017                         get { return XPathNodeType.ProcessingInstruction; }\r
1018                 }\r
1019 \r
1020                 public override string Value {\r
1021                         get { return value; }\r
1022                         set { this.value += value; }\r
1023                 }\r
1024 \r
1025                 internal override void BuildValue (StringBuilder sb)\r
1026                 {\r
1027                         sb.Append (value);\r
1028                 }\r
1029 \r
1030                 public override int ChildCount { get { return 0; } }\r
1031 \r
1032                 public override void WriteTo (XmlWriter writer)\r
1033                 {\r
1034                         writer.WriteProcessingInstruction (LocalName, Value);\r
1035                 }\r
1036         }\r
1037 \r
1038         public class XomText : XomNode\r
1039         {\r
1040                 string value;\r
1041 \r
1042                 public XomText (string value)\r
1043                         : this (value, null)\r
1044                 {\r
1045                 }\r
1046 \r
1047                 public XomText (string value, XomParentNode parent)\r
1048                 {\r
1049                         this.value = value;\r
1050                         if (parent != null)\r
1051                                 parent.AppendChild (this);\r
1052                 }\r
1053 \r
1054                 public override string Prefix {\r
1055                         get { return ""; }\r
1056                 }\r
1057 \r
1058                 public override string LocalName {\r
1059                         get { return ""; }\r
1060                 }\r
1061 \r
1062                 public override string Namespace {\r
1063                         get { return ""; }\r
1064                 }\r
1065 \r
1066                 public override string Value {\r
1067                         get { return value; }\r
1068                         set { this.value += value; }\r
1069                 }\r
1070 \r
1071                 public override XPathNodeType NodeType {\r
1072                         get { return XPathNodeType.Text; }\r
1073                 }\r
1074 \r
1075                 internal override void BuildValue (StringBuilder sb)\r
1076                 {\r
1077                         sb.Append (value);\r
1078                 }\r
1079 \r
1080                 public override int ChildCount { get { return 0; } }\r
1081 \r
1082                 public override void WriteTo (XmlWriter writer)\r
1083                 {\r
1084                         writer.WriteString (Value);\r
1085                 }\r
1086         }\r
1087 \r
1088         public class XomWhitespace : XomNode\r
1089         {\r
1090                 string value;\r
1091 \r
1092                 public XomWhitespace (string value)\r
1093                         : this (value, null)\r
1094                 {\r
1095                 }\r
1096 \r
1097                 public XomWhitespace (string value, XomParentNode parent)\r
1098                 {\r
1099                         this.value = value;\r
1100                         if (parent != null)\r
1101                                 parent.AppendChild (this);\r
1102                 }\r
1103 \r
1104                 public override string Prefix {\r
1105                         get { return ""; }\r
1106                 }\r
1107 \r
1108                 public override string LocalName {\r
1109                         get { return ""; }\r
1110                 }\r
1111 \r
1112                 public override string Namespace {\r
1113                         get { return ""; }\r
1114                 }\r
1115 \r
1116                 public override string Value {\r
1117                         get { return value; }\r
1118                         set { this.value += value; }\r
1119                 }\r
1120 \r
1121                 public override XPathNodeType NodeType {\r
1122                         get { return XPathNodeType.Whitespace; }\r
1123                 }\r
1124 \r
1125                 internal override void BuildValue (StringBuilder sb)\r
1126                 {\r
1127                         sb.Append (value);\r
1128                 }\r
1129 \r
1130                 public override int ChildCount { get { return 0; } }\r
1131 \r
1132                 public override void WriteTo (XmlWriter writer)\r
1133                 {\r
1134                         writer.WriteString (Value);\r
1135                 }\r
1136         }\r
1137 \r
1138         public class XomSignificantWhitespace : XomNode\r
1139         {\r
1140                 string value;\r
1141 \r
1142                 public XomSignificantWhitespace (string value)\r
1143                         : this (value, null)\r
1144                 {\r
1145                 }\r
1146 \r
1147                 public XomSignificantWhitespace (string value, XomParentNode parent)\r
1148                 {\r
1149                         this.value = value;\r
1150                         if (parent != null)\r
1151                                 parent.AppendChild (this);\r
1152                 }\r
1153 \r
1154                 public override string Prefix {\r
1155                         get { return ""; }\r
1156                 }\r
1157 \r
1158                 public override string LocalName {\r
1159                         get { return ""; }\r
1160                 }\r
1161 \r
1162                 public override string Namespace {\r
1163                         get { return ""; }\r
1164                 }\r
1165 \r
1166                 public override string Value {\r
1167                         get { return value; }\r
1168                         set { this.value += value; }\r
1169                 }\r
1170 \r
1171                 public override XPathNodeType NodeType {\r
1172                         get { return XPathNodeType.SignificantWhitespace; }\r
1173                 }\r
1174 \r
1175                 internal override void BuildValue (StringBuilder sb)\r
1176                 {\r
1177                         sb.Append (value);\r
1178                 }\r
1179 \r
1180                 public override int ChildCount { get { return 0; } }\r
1181 \r
1182                 public override void WriteTo (XmlWriter writer)\r
1183                 {\r
1184                         writer.WriteString (Value);\r
1185                 }\r
1186         }\r
1187 }\r
1188 #endif\r