5191bb1c5b7706b94385044d4db78c13f1fce4ac
[mono.git] / mcs / class / System.Xml.Linq / System.Xml.Linq / XNode.cs
1 //
2 // Authors:
3 //   Atsushi Enomoto
4 //
5 // Copyright 2007 Novell (http://www.novell.com)
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining
8 // a copy of this software and associated documentation files (the
9 // "Software"), to deal in the Software without restriction, including
10 // without limitation the rights to use, copy, modify, merge, publish,
11 // distribute, sublicense, and/or sell copies of the Software, and to
12 // permit persons to whom the Software is furnished to do so, subject to
13 // the following conditions:
14 // 
15 // The above copyright notice and this permission notice shall be
16 // included in all copies or substantial portions of the Software.
17 // 
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 //
26
27 using System;
28 using System.Collections;
29 using System.Collections.Generic;
30 using System.IO;
31 using System.Text;
32 using System.Xml;
33
34 using XPI = System.Xml.Linq.XProcessingInstruction;
35
36 namespace System.Xml.Linq
37 {
38         public abstract class XNode : XObject
39         {
40                 public static int CompareDocumentOrder (XNode n1, XNode n2)
41                 {
42                         return order_comparer.Compare (n1, n2);
43                 }
44
45                 public static bool DeepEquals (XNode n1, XNode n2)
46                 {
47                         return eq_comparer.Equals (n1, n2);
48                 }
49
50                 static XNodeEqualityComparer eq_comparer =
51                         new XNodeEqualityComparer ();
52                 static XNodeDocumentOrderComparer order_comparer =
53                         new XNodeDocumentOrderComparer ();
54
55                 XNode previous;
56                 XNode next;
57
58                 internal XNode ()
59                 {
60                 }
61
62                 public static XNodeDocumentOrderComparer DocumentOrderComparer {
63                         get { return order_comparer; }
64                 }
65
66                 public static XNodeEqualityComparer EqualityComparer {
67                         get { return eq_comparer; }
68                 }
69
70                 public XNode PreviousNode {
71                         get { return previous; }
72                         internal set { previous = value; }
73                 }
74
75                 public XNode NextNode {
76                         get { return next; }
77                         internal set { next = value; }
78                 }
79
80                 public string ToString (SaveOptions options)
81                 {
82                         StringWriter sw = new StringWriter ();
83                         XmlWriterSettings s = new XmlWriterSettings ();
84                         s.ConformanceLevel = ConformanceLevel.Auto;
85                         s.Indent = options != SaveOptions.DisableFormatting;
86                         XmlWriter xw = XmlWriter.Create (sw, s);
87                         WriteTo (xw);
88                         xw.Close ();
89                         return sw.ToString ();
90                 }
91
92                 public void AddAfterSelf (object content)
93                 {
94                         if (Parent == null)
95                                 throw new InvalidOperationException ();
96                         foreach (XNode n in XUtil.ToNodes (content)) {
97                                 n.SetOwner (Parent);
98                                 n.previous = this;
99                                 n.next = next;
100                                 if (next != null)
101                                         next.previous = n;
102                                 next = n;
103                                 if (Parent.LastNode == this)
104                                         Parent.LastNode = n;
105                         }
106                 }
107
108                 public void AddAfterSelf (params object [] content)
109                 {
110                         if (Parent == null)
111                                 throw new InvalidOperationException ();
112                         XNode n = this;
113                         foreach (object o in XUtil.ShrinkArray (content)) {
114                                 n.AddAfterSelf (o);
115                                 n = n.NextNode;
116                         }
117                 }
118
119                 public void AddBeforeSelf (object content)
120                 {
121                         if (Parent == null)
122                                 throw new InvalidOperationException ();
123                         foreach (XNode n in XUtil.ToNodes (content)) {
124                                 n.SetOwner (Parent);
125                                 n.previous = previous;
126                                 n.next = this;
127                                 if (previous != null)
128                                         previous.next = n;
129                                 previous = n;
130                                 if (Parent.FirstNode == this)
131                                         Parent.FirstNode = n;
132                         }
133                 }
134
135                 public void AddBeforeSelf (params object [] content)
136                 {
137                         if (Parent == null)
138                                 throw new InvalidOperationException ();
139                         foreach (object o in XUtil.ShrinkArray (content))
140                                 AddBeforeSelf (o);
141                 }
142
143                 public static XNode ReadFrom (XmlReader r)
144                 {
145                         return ReadFrom (r, LoadOptions.None);
146                 }
147
148                 internal static XNode ReadFrom (XmlReader r, LoadOptions options)
149                 {
150                         switch (r.NodeType) {
151                         case XmlNodeType.Element:
152                                 return XElement.LoadCore (r, options);
153                         case XmlNodeType.Whitespace:
154                         case XmlNodeType.SignificantWhitespace:
155                         case XmlNodeType.Text:
156                                 XText t = new XText (r.Value);
157                                 t.FillLineInfoAndBaseUri (r, options);
158                                 r.Read ();
159                                 return t;
160                         case XmlNodeType.CDATA:
161                                 XCData c = new XCData (r.Value);
162                                 c.FillLineInfoAndBaseUri (r, options);
163                                 r.Read ();
164                                 return c;
165                         case XmlNodeType.ProcessingInstruction:
166                                 XPI pi = new XPI (r.Name, r.Value);
167                                 pi.FillLineInfoAndBaseUri (r, options);
168                                 r.Read ();
169                                 return pi;
170                         case XmlNodeType.Comment:
171                                 XComment cm = new XComment (r.Value);
172                                 cm.FillLineInfoAndBaseUri (r, options);
173                                 r.Read ();
174                                 return cm;
175                         case XmlNodeType.DocumentType:
176                                 XDocumentType d = new XDocumentType (r.Name,
177                                         r.GetAttribute ("PUBLIC"),
178                                         r.GetAttribute ("System"),
179                                         r.Value);
180                                 d.FillLineInfoAndBaseUri (r, options);
181                                 r.Read ();
182                                 return d;
183                         default:
184                                 throw new InvalidOperationException (String.Format ("Node type {0} is not supported", r.NodeType));
185                         }
186                 }
187
188                 public void Remove ()
189                 {
190                         if (Parent == null)
191                                 throw new InvalidOperationException ("Parent is missing");
192
193                         if (Parent.FirstNode == this)
194                                 Parent.FirstNode = next;
195                         if (Parent.LastNode == this)
196                                 Parent.LastNode = previous;
197                         if (previous != null)
198                                 previous.next = next;
199                         if (next != null)
200                                 next.previous = previous;
201                         previous = null;
202                         next = null;
203                         SetOwner (null);
204                 }
205
206                 public override string ToString ()
207                 {
208                         return ToString (SaveOptions.None);
209                 }
210
211                 public abstract void WriteTo (XmlWriter w);
212
213                 public IEnumerable<XElement> Ancestors ()
214                 {
215                         for (XElement el = Parent; el != null; el = el.Parent)
216                                 yield return el;
217                 }
218
219                 public IEnumerable<XElement> Ancestors (XName name)
220                 {
221                         foreach (XElement el in Ancestors ())
222                                 if (el.Name == name)
223                                         yield return el;
224                 }
225
226                 public XmlReader CreateReader ()
227                 {
228                         return new XNodeReader (this);
229                 }
230
231                 public IEnumerable<XElement> ElementsAfterSelf ()
232                 {
233                         foreach (XNode n in NodesAfterSelf ())
234                                 if (n is XElement)
235                                         yield return (XElement) n;
236                 }
237
238                 public IEnumerable<XElement> ElementsAfterSelf (XName name)
239                 {
240                         foreach (XElement el in ElementsAfterSelf ())
241                                 if (el.Name == name)
242                                         yield return el;
243                 }
244
245                 public IEnumerable<XElement> ElementsBeforeSelf ()
246                 {
247                         foreach (XNode n in NodesBeforeSelf ())
248                                 if (n is XElement)
249                                         yield return (XElement) n;
250                 }
251
252                 public IEnumerable<XElement> ElementsBeforeSelf (XName name)
253                 {
254                         foreach (XElement el in ElementsBeforeSelf ())
255                                 if (el.Name == name)
256                                         yield return el;
257                 }
258
259                 public bool IsAfter (XNode other)
260                 {
261                         return XNode.DocumentOrderComparer.Compare (this, other) > 0;
262                 }
263
264                 public bool IsBefore (XNode other)
265                 {
266                         return XNode.DocumentOrderComparer.Compare (this, other) < 0;
267                 }
268
269                 public IEnumerable<XNode> NodesAfterSelf ()
270                 {
271                         if (Parent == null)
272                                 yield break;
273                         for (XNode n = NextNode; n != null; n = n.NextNode)
274                                 yield return n;
275                 }
276
277                 public IEnumerable<XNode> NodesBeforeSelf ()
278                 {
279                         for (XNode n = Parent.FirstNode; n != this; n = n.NextNode)
280                                 yield return n;
281                 }
282
283                 public void ReplaceWith (object item)
284                 {
285                         AddAfterSelf (item);
286                         Remove ();
287                 }
288
289                 public void ReplaceWith (params object [] items)
290                 {
291                         AddAfterSelf (items);
292                         Remove ();
293                 }
294         }
295 }