5 // Copyright 2007 Novell (http://www.novell.com)
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:
15 // The above copyright notice and this permission notice shall be
16 // included in all copies or substantial portions of the Software.
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.
28 using System.Collections;
29 using System.Collections.Generic;
34 using XPI = System.Xml.Linq.XProcessingInstruction;
36 namespace System.Xml.Linq
38 public abstract class XNode : XObject
40 public static int CompareDocumentOrder (XNode n1, XNode n2)
42 return order_comparer.Compare (n1, n2);
45 public static bool DeepEquals (XNode n1, XNode n2)
47 return eq_comparer.Equals (n1, n2);
50 static XNodeEqualityComparer eq_comparer =
51 new XNodeEqualityComparer ();
52 static XNodeDocumentOrderComparer order_comparer =
53 new XNodeDocumentOrderComparer ();
62 public static XNodeDocumentOrderComparer DocumentOrderComparer {
63 get { return order_comparer; }
66 public static XNodeEqualityComparer EqualityComparer {
67 get { return eq_comparer; }
70 public XNode PreviousNode {
71 get { return previous; }
72 internal set { previous = value; }
75 public XNode NextNode {
77 internal set { next = value; }
80 public string ToString (SaveOptions options)
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);
90 return sw.ToString ();
93 public void AddAfterSelf (object content)
96 throw new InvalidOperationException ();
99 foreach (object o in XUtil.ExpandArray (content)) {
100 if (o == null || Owner.OnAddingObject (o, true, here, false))
102 XNode n = XUtil.ToNode (o);
103 Owner.OnAddingObject (n);
104 n = (XNode) XUtil.GetDetachedObject (n);
110 orgNext.previous = n;
114 Owner.OnAddedObject (n);
118 public void AddAfterSelf (params object [] content)
121 throw new InvalidOperationException ();
122 AddAfterSelf ((object) content);
125 public void AddBeforeSelf (object content)
128 throw new InvalidOperationException ();
129 foreach (object o in XUtil.ExpandArray (content)) {
130 if (o == null || Owner.OnAddingObject (o, true, previous, true))
133 XNode n = XUtil.ToNode (o);
134 Owner.OnAddingObject (n);
135 n = (XNode) XUtil.GetDetachedObject (n);
137 n.previous = previous;
139 if (previous != null)
142 if (Owner.FirstNode == this)
144 Owner.OnAddedObject (n);
148 public void AddBeforeSelf (params object [] content)
151 throw new InvalidOperationException ();
152 AddBeforeSelf ((object) content);
155 public static XNode ReadFrom (XmlReader reader)
157 return ReadFrom (reader, LoadOptions.None);
160 internal static XNode ReadFrom (XmlReader r, LoadOptions options)
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);
172 case XmlNodeType.CDATA:
173 XCData c = new XCData (r.Value);
174 c.FillLineInfoAndBaseUri (r, options);
177 case XmlNodeType.ProcessingInstruction:
178 XPI pi = new XPI (r.Name, r.Value);
179 pi.FillLineInfoAndBaseUri (r, options);
182 case XmlNodeType.Comment:
183 XComment cm = new XComment (r.Value);
184 cm.FillLineInfoAndBaseUri (r, options);
187 case XmlNodeType.DocumentType:
188 XDocumentType d = new XDocumentType (r.Name,
189 r.GetAttribute ("PUBLIC"),
190 r.GetAttribute ("SYSTEM"),
192 d.FillLineInfoAndBaseUri (r, options);
196 throw new InvalidOperationException (String.Format ("Node type {0} is not supported", r.NodeType));
200 public void Remove ()
203 throw new InvalidOperationException ("Owner is missing");
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;
214 next.previous = previous;
218 owner.OnRemovedObject (this);
221 public override string ToString ()
223 return ToString (SaveOptions.None);
226 public abstract void WriteTo (XmlWriter writer);
228 public IEnumerable<XElement> Ancestors ()
230 for (XElement el = Parent; el != null; el = el.Parent)
234 public IEnumerable<XElement> Ancestors (XName name)
236 foreach (XElement el in Ancestors ())
241 public XmlReader CreateReader ()
243 return new XNodeReader (this);
247 public XmlReader CreateReader (ReaderOptions readerOptions)
249 var r = new XNodeReader (this);
250 if ((readerOptions & ReaderOptions.OmitDuplicateNamespaces) != 0)
251 r.OmitDuplicateNamespaces = true;
257 public IEnumerable<XElement> ElementsAfterSelf ()
259 foreach (XNode n in NodesAfterSelf ())
261 yield return (XElement) n;
264 public IEnumerable<XElement> ElementsAfterSelf (XName name)
266 foreach (XElement el in ElementsAfterSelf ())
271 public IEnumerable<XElement> ElementsBeforeSelf ()
273 foreach (XNode n in NodesBeforeSelf ())
275 yield return (XElement) n;
278 public IEnumerable<XElement> ElementsBeforeSelf (XName name)
280 foreach (XElement el in ElementsBeforeSelf ())
285 public bool IsAfter (XNode node)
287 return XNode.DocumentOrderComparer.Compare (this, node) > 0;
290 public bool IsBefore (XNode node)
292 return XNode.DocumentOrderComparer.Compare (this, node) < 0;
295 public IEnumerable<XNode> NodesAfterSelf ()
299 for (XNode n = NextNode; n != null; n = n.NextNode)
303 public IEnumerable<XNode> NodesBeforeSelf ()
307 for (XNode n = Owner.FirstNode; n != this; n = n.NextNode)
311 public void ReplaceWith (object content)
314 throw new InvalidOperationException ();
316 XNode here = previous;
317 XNode orgNext = next;
318 XContainer orgOwner = Owner;
320 foreach (object o in XUtil.ExpandArray (content)) {
321 if (o == null || orgOwner.OnAddingObject (o, true, here, false))
323 XNode n = XUtil.ToNode (o);
324 n = (XNode) XUtil.GetDetachedObject (n);
325 n.SetOwner (orgOwner);
330 orgOwner.FirstNode = n;
333 orgNext.previous = n;
335 orgOwner.LastNode = n;
340 public void ReplaceWith (params object [] content)
343 throw new InvalidOperationException ();
344 ReplaceWith ((object) content);