Merge pull request #1319 from directhex/systemwide-per-arch-aot-cache
[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                                 ConformanceLevel = ConformanceLevel.Auto,
85                                 Indent = options != SaveOptions.DisableFormatting,
86                                 OmitXmlDeclaration = true };
87                         XmlWriter xw = XmlWriter.Create (sw, s);
88                         WriteTo (xw);
89                         xw.Close ();
90                         return sw.ToString ();
91                 }
92
93                 public void AddAfterSelf (object content)
94                 {
95                         if (Owner == null)
96                                 throw new InvalidOperationException ();
97                         XNode here = this;
98                         XNode orgNext = next;
99                         foreach (object o in XUtil.ExpandArray (content)) {
100                                 if (o == null || Owner.OnAddingObject (o, true, here, false))
101                                         continue;
102                                 XNode n = XUtil.ToNode (o);
103                                 Owner.OnAddingObject (n);
104                                 n = (XNode) XUtil.GetDetachedObject (n);
105                                 n.SetOwner (Owner);
106                                 n.previous = here;
107                                 here.next = n;
108                                 n.next = orgNext;
109                                 if (orgNext != null)
110                                         orgNext.previous = n;
111                                 else
112                                         Owner.LastNode = n;
113                                 here = n;
114                                 Owner.OnAddedObject (n);
115                         }
116                 }
117
118                 public void AddAfterSelf (params object [] content)
119                 {
120                         if (Owner == null)
121                                 throw new InvalidOperationException ();
122                         AddAfterSelf ((object) content);
123                 }
124
125                 public void AddBeforeSelf (object content)
126                 {
127                         if (Owner == null)
128                                 throw new InvalidOperationException ();
129                         foreach (object o in XUtil.ExpandArray (content)) {
130                                 if (o == null || Owner.OnAddingObject (o, true, previous, true))
131                                         continue;
132
133                                 XNode n = XUtil.ToNode (o);
134                                 Owner.OnAddingObject (n);
135                                 n = (XNode) XUtil.GetDetachedObject (n);
136                                 n.SetOwner (Owner);
137                                 n.previous = previous;
138                                 n.next = this;
139                                 if (previous != null)
140                                         previous.next = n;
141                                 previous = n;
142                                 if (Owner.FirstNode == this)
143                                         Owner.FirstNode = n;
144                                 Owner.OnAddedObject (n);
145                         }
146                 }
147
148                 public void AddBeforeSelf (params object [] content)
149                 {
150                         if (Owner == null)
151                                 throw new InvalidOperationException ();
152                         AddBeforeSelf ((object) content);
153                 }
154
155                 public static XNode ReadFrom (XmlReader reader)
156                 {
157                         return ReadFrom (reader, LoadOptions.None);
158                 }
159
160                 internal static XNode ReadFrom (XmlReader r, LoadOptions options)
161                 {
162                         switch (r.NodeType) {
163                         case XmlNodeType.Element:
164                                 return XElement.LoadCore (r, options);
165                         case XmlNodeType.Whitespace:
166                         case XmlNodeType.SignificantWhitespace:
167                         case XmlNodeType.Text:
168                                 XText t = new XText (r.Value);
169                                 t.FillLineInfoAndBaseUri (r, options);
170                                 r.Read ();
171                                 return t;
172                         case XmlNodeType.CDATA:
173                                 XCData c = new XCData (r.Value);
174                                 c.FillLineInfoAndBaseUri (r, options);
175                                 r.Read ();
176                                 return c;
177                         case XmlNodeType.ProcessingInstruction:
178                                 XPI pi = new XPI (r.Name, r.Value);
179                                 pi.FillLineInfoAndBaseUri (r, options);
180                                 r.Read ();
181                                 return pi;
182                         case XmlNodeType.Comment:
183                                 XComment cm = new XComment (r.Value);
184                                 cm.FillLineInfoAndBaseUri (r, options);
185                                 r.Read ();
186                                 return cm;
187                         case XmlNodeType.DocumentType:
188                                 XDocumentType d = new XDocumentType (r.Name,
189                                         r.GetAttribute ("PUBLIC"),
190                                         r.GetAttribute ("SYSTEM"),
191                                         r.Value);
192                                 d.FillLineInfoAndBaseUri (r, options);
193                                 r.Read ();
194                                 return d;
195                         default:
196                                 throw new InvalidOperationException (String.Format ("Node type {0} is not supported", r.NodeType));
197                         }
198                 }
199
200                 public void Remove ()
201                 {
202                         if (Owner == null)
203                                 throw new InvalidOperationException ("Owner is missing");
204
205                         var owner = Owner;
206                         owner.OnRemovingObject (this);
207                         if (Owner.FirstNode == this)
208                                 Owner.FirstNode = next;
209                         if (Owner.LastNode == this)
210                                 Owner.LastNode = previous;
211                         if (previous != null)
212                                 previous.next = next;
213                         if (next != null)
214                                 next.previous = previous;
215                         previous = null;
216                         next = null;
217                         SetOwner (null);
218                         owner.OnRemovedObject (this);
219                 }
220
221                 public override string ToString ()
222                 {
223                         return ToString (SaveOptions.None);
224                 }
225
226                 public abstract void WriteTo (XmlWriter writer);
227
228                 public IEnumerable<XElement> Ancestors ()
229                 {
230                         for (XElement el = Parent; el != null; el = el.Parent)
231                                 yield return el;
232                 }
233
234                 public IEnumerable<XElement> Ancestors (XName name)
235                 {
236                         foreach (XElement el in Ancestors ())
237                                 if (el.Name == name)
238                                         yield return el;
239                 }
240
241                 public XmlReader CreateReader ()
242                 {
243                         return new XNodeReader (this);
244                 }
245
246 #if NET_4_0
247                 public XmlReader CreateReader (ReaderOptions readerOptions)
248                 {
249                         var r = new XNodeReader (this);
250                         if ((readerOptions & ReaderOptions.OmitDuplicateNamespaces) != 0)
251                                 r.OmitDuplicateNamespaces = true;
252                         
253                         return r;
254                 }
255 #endif
256
257                 public IEnumerable<XElement> ElementsAfterSelf ()
258                 {
259                         foreach (XNode n in NodesAfterSelf ())
260                                 if (n is XElement)
261                                         yield return (XElement) n;
262                 }
263
264                 public IEnumerable<XElement> ElementsAfterSelf (XName name)
265                 {
266                         foreach (XElement el in ElementsAfterSelf ())
267                                 if (el.Name == name)
268                                         yield return el;
269                 }
270
271                 public IEnumerable<XElement> ElementsBeforeSelf ()
272                 {
273                         foreach (XNode n in NodesBeforeSelf ())
274                                 if (n is XElement)
275                                         yield return (XElement) n;
276                 }
277
278                 public IEnumerable<XElement> ElementsBeforeSelf (XName name)
279                 {
280                         foreach (XElement el in ElementsBeforeSelf ())
281                                 if (el.Name == name)
282                                         yield return el;
283                 }
284
285                 public bool IsAfter (XNode node)
286                 {
287                         return XNode.DocumentOrderComparer.Compare (this, node) > 0;
288                 }
289
290                 public bool IsBefore (XNode node)
291                 {
292                         return XNode.DocumentOrderComparer.Compare (this, node) < 0;
293                 }
294
295                 public IEnumerable<XNode> NodesAfterSelf ()
296                 {
297                         if (Owner == null)
298                                 yield break;
299                         for (XNode n = NextNode; n != null; n = n.NextNode)
300                                 yield return n;
301                 }
302
303                 public IEnumerable<XNode> NodesBeforeSelf ()
304                 {
305                         if (Owner == null)
306                                 yield break;
307                         for (XNode n = Owner.FirstNode; n != this; n = n.NextNode)
308                                 yield return n;
309                 }
310
311                 public void ReplaceWith (object content)
312                 {
313                         if (Owner == null)
314                                 throw new InvalidOperationException ();
315
316                         XNode here = previous;
317                         XNode orgNext = next;
318                         XContainer orgOwner = Owner;
319                         Remove();
320                         foreach (object o in XUtil.ExpandArray (content)) {
321                                 if (o == null || orgOwner.OnAddingObject (o, true, here, false))
322                                         continue;
323                                 XNode n = XUtil.ToNode (o);
324                                 n = (XNode) XUtil.GetDetachedObject (n);
325                                 n.SetOwner (orgOwner);
326                                 n.previous = here;
327                                 if (here != null)
328                                         here.next = n;
329                                 else
330                                         orgOwner.FirstNode = n;
331                                 n.next = orgNext;
332                                 if (orgNext != null)
333                                         orgNext.previous = n;
334                                 else
335                                         orgOwner.LastNode = n;
336                                 here = n;
337                         }
338                 }
339
340                 public void ReplaceWith (params object [] content)
341                 {
342                         if (Owner == null)
343                                 throw new InvalidOperationException ();
344                         ReplaceWith ((object) content);
345                 }
346         }
347 }