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;
33 using System.Xml.Schema;
34 using System.Xml.Serialization;
36 namespace System.Xml.Linq
38 [XmlSchemaProvider (null, IsAny = true)]
39 public class XElement : XContainer, IXmlSerializable
41 static IEnumerable <XElement> emptySequence =
42 new List <XElement> ();
44 public static IEnumerable <XElement> EmptySequence {
45 get { return emptySequence; }
49 XAttribute attr_first, attr_last;
50 bool explicit_is_empty = true;
52 public XElement (XName name, object value)
58 public XElement (XElement source)
61 Add (source.Nodes ());
64 public XElement (XName name)
69 public XElement (XName name, params object [] contents)
75 public XElement (XStreamingElement source)
77 this.name = source.Name;
78 Add (source.Contents);
81 public static explicit operator bool (XElement element)
84 throw new ArgumentNullException ("element");
85 return XmlConvert.ToBoolean (element.Value);
88 public static explicit operator bool? (XElement element)
93 return element.Value == null ? (bool?) null : XmlConvert.ToBoolean (element.Value);
96 public static explicit operator DateTime (XElement element)
99 throw new ArgumentNullException ("element");
100 return XmlConvert.ToDateTime (element.Value, XmlDateTimeSerializationMode.RoundtripKind);
103 public static explicit operator DateTime? (XElement element)
108 return element.Value == null ? (DateTime?) null : XmlConvert.ToDateTime (element.Value, XmlDateTimeSerializationMode.RoundtripKind);
111 public static explicit operator decimal (XElement element)
114 throw new ArgumentNullException ("element");
115 return XmlConvert.ToDecimal (element.Value);
118 public static explicit operator decimal? (XElement element)
123 return element.Value == null ? (decimal?) null : XmlConvert.ToDecimal (element.Value);
126 public static explicit operator double (XElement element)
129 throw new ArgumentNullException ("element");
130 return XmlConvert.ToDouble (element.Value);
133 public static explicit operator double? (XElement element)
138 return element.Value == null ? (double?) null : XmlConvert.ToDouble (element.Value);
141 public static explicit operator float (XElement element)
144 throw new ArgumentNullException ("element");
145 return XmlConvert.ToSingle (element.Value);
148 public static explicit operator float? (XElement element)
153 return element.Value == null ? (float?) null : XmlConvert.ToSingle (element.Value);
156 public static explicit operator Guid (XElement element)
159 throw new ArgumentNullException ("element");
160 return XmlConvert.ToGuid (element.Value);
163 public static explicit operator Guid? (XElement element)
168 return element.Value == null ? (Guid?) null : XmlConvert.ToGuid (element.Value);
171 public static explicit operator int (XElement element)
174 throw new ArgumentNullException ("element");
175 return XmlConvert.ToInt32 (element.Value);
178 public static explicit operator int? (XElement element)
183 return element.Value == null ? (int?) null : XmlConvert.ToInt32 (element.Value);
186 public static explicit operator long (XElement element)
189 throw new ArgumentNullException ("element");
190 return XmlConvert.ToInt64 (element.Value);
193 public static explicit operator long? (XElement element)
198 return element.Value == null ? (long?) null : XmlConvert.ToInt64 (element.Value);
201 [CLSCompliant (false)]
202 public static explicit operator uint (XElement element)
205 throw new ArgumentNullException ("element");
206 return XmlConvert.ToUInt32 (element.Value);
209 [CLSCompliant (false)]
210 public static explicit operator uint? (XElement element)
215 return element.Value == null ? (uint?) null : XmlConvert.ToUInt32 (element.Value);
218 [CLSCompliant (false)]
219 public static explicit operator ulong (XElement element)
222 throw new ArgumentNullException ("element");
223 return XmlConvert.ToUInt64 (element.Value);
226 [CLSCompliant (false)]
227 public static explicit operator ulong? (XElement element)
232 return element.Value == null ? (ulong?) null : XmlConvert.ToUInt64 (element.Value);
235 public static explicit operator TimeSpan (XElement element)
238 throw new ArgumentNullException ("element");
239 return XmlConvert.ToTimeSpan (element.Value);
242 public static explicit operator TimeSpan? (XElement element)
247 return element.Value == null ? (TimeSpan?) null : XmlConvert.ToTimeSpan (element.Value);
250 public static explicit operator string (XElement element)
255 return element.Value;
258 public XAttribute FirstAttribute {
259 get { return attr_first; }
260 internal set { attr_first = value; }
263 public XAttribute LastAttribute {
264 get { return attr_last; }
265 internal set { attr_last = value; }
268 public bool HasAttributes {
269 get { return attr_first != null; }
272 public bool HasElements {
274 foreach (object o in Nodes ())
281 public bool IsEmpty {
282 get { return !Nodes ().GetEnumerator ().MoveNext () && explicit_is_empty; }
283 internal set { explicit_is_empty = value; }
290 throw new ArgumentNullException ("value");
295 public override XmlNodeType NodeType {
296 get { return XmlNodeType.Element; }
299 public string Value {
301 StringBuilder sb = null;
302 foreach (XNode n in Nodes ()) {
304 sb = new StringBuilder ();
306 sb.Append (((XText) n).Value);
307 else if (n is XElement)
308 sb.Append (((XElement) n).Value);
310 return sb == null ? String.Empty : sb.ToString ();
318 IEnumerable <XElement> GetAncestorList (XName name, bool getMeIn)
320 List <XElement> list = new List <XElement> ();
323 for (XElement el = Parent as XElement; el != null; el = el.Parent as XElement)
324 if (name == null || el.Name == name)
329 public XAttribute Attribute (XName name)
331 foreach (XAttribute a in Attributes ())
337 public IEnumerable <XAttribute> Attributes ()
340 for (XAttribute a = attr_first; a != null; a = next) {
341 next = a.NextAttribute;
347 public IEnumerable <XAttribute> Attributes (XName name)
349 foreach (XAttribute a in Attributes ())
354 public static XElement Load (string uri)
356 return Load (uri, LoadOptions.None);
359 public static XElement Load (string uri, LoadOptions options)
361 XmlReaderSettings s = new XmlReaderSettings ();
362 s.ProhibitDtd = false;
363 s.IgnoreWhitespace = (options & LoadOptions.PreserveWhitespace) == 0;
364 using (XmlReader r = XmlReader.Create (uri, s)) {
365 return LoadCore (r, options);
369 public static XElement Load (TextReader tr)
371 return Load (tr, LoadOptions.None);
374 public static XElement Load (TextReader tr, LoadOptions options)
376 XmlReaderSettings s = new XmlReaderSettings ();
377 s.ProhibitDtd = false;
378 s.IgnoreWhitespace = (options & LoadOptions.PreserveWhitespace) == 0;
379 using (XmlReader r = XmlReader.Create (tr, s)) {
380 return LoadCore (r, options);
384 public static XElement Load (XmlReader reader)
386 return Load (reader, LoadOptions.None);
389 public static XElement Load (XmlReader reader, LoadOptions options)
391 XmlReaderSettings s = reader.Settings.Clone ();
392 s.ProhibitDtd = false;
393 s.IgnoreWhitespace = (options & LoadOptions.PreserveWhitespace) == 0;
394 using (XmlReader r = XmlReader.Create (reader, s)) {
395 return LoadCore (r, options);
399 internal static XElement LoadCore (XmlReader r, LoadOptions options)
402 if (r.NodeType != XmlNodeType.Element)
403 throw new InvalidOperationException ("The XmlReader must be positioned at an element");
404 XName name = XName.Get (r.LocalName, r.NamespaceURI);
405 XElement e = new XElement (name);
406 e.FillLineInfoAndBaseUri (r, options);
408 if (r.MoveToFirstAttribute ()) {
410 // not sure how current Orcas behavior makes sense here though ...
411 if (r.LocalName == "xmlns" && r.NamespaceURI == XNamespace.Xmlns.NamespaceName)
412 e.SetAttributeValue (XNamespace.None.GetName ("xmlns"), r.Value);
414 e.SetAttributeValue (XName.Get (r.LocalName, r.NamespaceURI), r.Value);
415 e.LastAttribute.FillLineInfoAndBaseUri (r, options);
416 } while (r.MoveToNextAttribute ());
419 if (!r.IsEmptyElement) {
421 e.ReadContentFrom (r, options);
423 e.explicit_is_empty = false;
425 e.explicit_is_empty = true;
431 public static XElement Parse (string s)
433 return Parse (s, LoadOptions.None);
436 public static XElement Parse (string s, LoadOptions options)
438 return Load (new StringReader (s), options);
441 public void RemoveAll ()
447 public void RemoveAttributes ()
449 while (attr_first != null)
453 public void Save (string filename)
455 Save (filename, SaveOptions.None);
458 public void Save (string filename, SaveOptions options)
460 XmlWriterSettings s = new XmlWriterSettings ();
461 s.Indent = options != SaveOptions.DisableFormatting;
462 using (XmlWriter w = XmlWriter.Create (filename, s)) {
467 public void Save (TextWriter tw)
469 Save (tw, SaveOptions.None);
472 public void Save (TextWriter tw, SaveOptions options)
474 XmlWriterSettings s = new XmlWriterSettings ();
475 s.Indent = options != SaveOptions.DisableFormatting;
476 using (XmlWriter w = XmlWriter.Create (tw, s)) {
481 public void Save (XmlWriter w)
486 public IEnumerable <XElement> AncestorsAndSelf ()
488 return GetAncestorList (null, true);
491 public IEnumerable <XElement> AncestorsAndSelf (XName name)
493 return GetAncestorList (name, true);
496 public IEnumerable <XElement> DescendantsAndSelf ()
498 List <XElement> list = new List <XElement> ();
500 list.AddRange (Descendants ());
504 public IEnumerable <XElement> DescendantsAndSelf (XName name)
506 List <XElement> list = new List <XElement> ();
507 if (name == this.name)
509 list.AddRange (Descendants (name));
513 public IEnumerable <XNode> DescendantNodesAndSelf ()
516 foreach (XNode node in DescendantNodes ())
520 public void SetAttributeValue (XName name, object value)
522 XAttribute a = Attribute (name);
528 SetAttributeObject (new XAttribute (name, value));
531 a.Value = XUtil.ToString (value);
535 void SetAttributeObject (XAttribute a)
538 if (attr_first == null) {
542 attr_last.NextAttribute = a;
543 a.PreviousAttribute = attr_last;
548 public override void WriteTo (XmlWriter w)
550 w.WriteStartElement (name.LocalName, name.Namespace.NamespaceName);
552 foreach (XAttribute a in Attributes ()) {
553 if (a.IsNamespaceDeclaration) {
554 if (a.Name.Namespace == XNamespace.Xmlns)
555 w.WriteAttributeString ("xmlns", a.Name.LocalName, XNamespace.Xmlns.NamespaceName, a.Value);
557 w.WriteAttributeString ("xmlns", a.Value);
560 w.WriteAttributeString (a.Name.LocalName, a.Name.Namespace.NamespaceName, a.Value);
563 foreach (XNode node in Nodes ())
566 if (explicit_is_empty)
567 w.WriteEndElement ();
569 w.WriteFullEndElement ();
572 public XNamespace GetDefaultNamespace ()
574 for (XElement el = this; el != null; el = el.Parent)
575 foreach (XAttribute a in el.Attributes ())
576 if (a.IsNamespaceDeclaration && a.Name.Namespace == XNamespace.None)
577 return XNamespace.Get (a.Value);
578 return XNamespace.None; // nothing is declared.
581 public XNamespace GetNamespaceOfPrefix (string prefix)
583 for (XElement el = this; el != null; el = el.Parent)
584 foreach (XAttribute a in el.Attributes ())
585 if (a.IsNamespaceDeclaration && a.Name.LocalName == prefix)
586 return XNamespace.Get (a.Value);
587 return XNamespace.None; // nothing is declared.
590 public string GetPrefixOfNamespace (XNamespace ns)
592 foreach (string prefix in GetPrefixOfNamespaceCore (ns))
593 if (GetNamespaceOfPrefix (prefix) == ns)
595 return null; // nothing is declared
598 IEnumerable<string> GetPrefixOfNamespaceCore (XNamespace ns)
600 for (XElement el = this; el != null; el = el.Parent)
601 foreach (XAttribute a in el.Attributes ())
602 if (a.IsNamespaceDeclaration && a.Value == ns.NamespaceName)
603 yield return a.Name.Namespace == XNamespace.None ? String.Empty : a.Name.LocalName;
606 public void ReplaceAll (object item)
612 public void ReplaceAll (params object [] items)
618 public void ReplaceAttributes (object item)
624 public void ReplaceAttributes (params object [] items)
630 public void SetElementValue (XName name, object value)
632 XElement el = new XElement (name, value);
637 public void SetValue (object value)
640 throw new ArgumentNullException ("value");
641 if (value is XAttribute || value is XDocument || value is XDeclaration || value is XDocumentType)
642 throw new ArgumentException (String.Format ("Node type {0} is not allowed as element value", value.GetType ()));
644 foreach (XNode n in XUtil.ToNodes (value))
648 internal override bool OnAddingObject (object o)
650 XAttribute a = o as XAttribute;
652 foreach (XAttribute ia in Attributes ())
653 if (a.Name == ia.Name)
654 throw new InvalidOperationException (String.Format ("Duplicate attribute: {0}", a.Name));
655 SetAttributeObject (a);
658 else if (o is string && LastNode is XText) {
659 ((XText) LastNode).Value += o as string;
666 internal override void OnAdded (XNode node, bool addFirst)
668 if (node is XDocument || node is XDocumentType || node is XDeclaration)
669 throw new ArgumentException (String.Format ("A node of type {0} cannot be added as a content", node.GetType ()));
672 void IXmlSerializable.WriteXml (XmlWriter writer)
677 void IXmlSerializable.ReadXml (XmlReader reader)
679 ReadContentFrom (reader, LoadOptions.None);
682 XmlSchema IXmlSerializable.GetSchema ()