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)
76 public XElement (XStreamingElement source)
78 this.name = source.Name;
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)
91 throw new ArgumentNullException ("element");
92 return element.Value == null ? (bool?) null : XmlConvert.ToBoolean (element.Value);
95 public static explicit operator DateTime (XElement element)
98 throw new ArgumentNullException ("element");
99 return XmlConvert.ToDateTime (element.Value, XmlDateTimeSerializationMode.RoundtripKind);
102 public static explicit operator DateTime? (XElement element)
105 throw new ArgumentNullException ("element");
106 return element.Value == null ? (DateTime?) null : XmlConvert.ToDateTime (element.Value, XmlDateTimeSerializationMode.RoundtripKind);
109 public static explicit operator decimal (XElement element)
112 throw new ArgumentNullException ("element");
113 return XmlConvert.ToDecimal (element.Value);
116 public static explicit operator decimal? (XElement element)
119 throw new ArgumentNullException ("element");
120 return element.Value == null ? (decimal?) null : XmlConvert.ToDecimal (element.Value);
123 public static explicit operator double (XElement element)
126 throw new ArgumentNullException ("element");
127 return XmlConvert.ToDouble (element.Value);
130 public static explicit operator double? (XElement element)
133 throw new ArgumentNullException ("element");
134 return element.Value == null ? (double?) null : XmlConvert.ToDouble (element.Value);
137 public static explicit operator float (XElement element)
140 throw new ArgumentNullException ("element");
141 return XmlConvert.ToSingle (element.Value);
144 public static explicit operator float? (XElement element)
147 throw new ArgumentNullException ("element");
148 return element.Value == null ? (float?) null : XmlConvert.ToSingle (element.Value);
151 public static explicit operator Guid (XElement element)
154 throw new ArgumentNullException ("element");
155 return XmlConvert.ToGuid (element.Value);
158 public static explicit operator Guid? (XElement element)
161 throw new ArgumentNullException ("element");
162 return element.Value == null ? (Guid?) null : XmlConvert.ToGuid (element.Value);
165 public static explicit operator int (XElement element)
168 throw new ArgumentNullException ("element");
169 return XmlConvert.ToInt32 (element.Value);
172 public static explicit operator int? (XElement element)
175 throw new ArgumentNullException ("element");
176 return element.Value == null ? (int?) null : XmlConvert.ToInt32 (element.Value);
179 public static explicit operator long (XElement element)
182 throw new ArgumentNullException ("element");
183 return XmlConvert.ToInt64 (element.Value);
186 public static explicit operator long? (XElement element)
189 throw new ArgumentNullException ("element");
190 return element.Value == null ? (long?) null : XmlConvert.ToInt64 (element.Value);
193 [CLSCompliant (false)]
194 public static explicit operator uint (XElement element)
197 throw new ArgumentNullException ("element");
198 return XmlConvert.ToUInt32 (element.Value);
201 [CLSCompliant (false)]
202 public static explicit operator uint? (XElement element)
205 throw new ArgumentNullException ("element");
206 return element.Value == null ? (uint?) null : XmlConvert.ToUInt32 (element.Value);
209 [CLSCompliant (false)]
210 public static explicit operator ulong (XElement element)
213 throw new ArgumentNullException ("element");
214 return XmlConvert.ToUInt64 (element.Value);
217 [CLSCompliant (false)]
218 public static explicit operator ulong? (XElement element)
221 throw new ArgumentNullException ("element");
222 return element.Value == null ? (ulong?) null : XmlConvert.ToUInt64 (element.Value);
225 public static explicit operator TimeSpan (XElement element)
228 throw new ArgumentNullException ("element");
229 return XmlConvert.ToTimeSpan (element.Value);
232 public static explicit operator TimeSpan? (XElement element)
235 throw new ArgumentNullException ("element");
236 return element.Value == null ? (TimeSpan?) null : XmlConvert.ToTimeSpan (element.Value);
239 public static explicit operator string (XElement element)
242 throw new ArgumentNullException ("element");
243 return element.Value;
246 public XAttribute FirstAttribute {
247 get { return attr_first; }
248 internal set { attr_first = value; }
251 public XAttribute LastAttribute {
252 get { return attr_last; }
253 internal set { attr_last = value; }
256 public bool HasAttributes {
257 get { return attr_first != null; }
260 public bool HasElements {
262 foreach (object o in Nodes ())
269 public bool IsEmpty {
270 get { return !Nodes ().GetEnumerator ().MoveNext () && explicit_is_empty; }
271 internal set { explicit_is_empty = value; }
278 throw new ArgumentNullException ("value");
283 public override XmlNodeType NodeType {
284 get { return XmlNodeType.Element; }
287 public string Value {
289 StringBuilder sb = null;
290 foreach (object s in Nodes ()) {
292 sb = new StringBuilder ();
295 return sb == null ? String.Empty : sb.ToString ();
303 IEnumerable <XElement> GetAncestorList (XName name, bool getMeIn)
305 List <XElement> list = new List <XElement> ();
308 for (XElement el = Parent as XElement; el != null; el = el.Parent as XElement)
309 if (name == null || el.Name == name)
314 public XAttribute Attribute (XName name)
316 foreach (XAttribute a in Attributes ())
322 public IEnumerable <XAttribute> Attributes ()
325 for (XAttribute a = attr_first; a != null; a = next) {
326 next = a.NextAttribute;
332 public IEnumerable <XAttribute> Attributes (XName name)
334 foreach (XAttribute a in Attributes ())
339 public static XElement Load (string uri)
341 return Load (uri, LoadOptions.None);
344 public static XElement Load (string uri, LoadOptions options)
346 XmlReaderSettings s = new XmlReaderSettings ();
347 s.IgnoreWhitespace = (options & LoadOptions.PreserveWhitespace) == 0;
348 using (XmlReader r = XmlReader.Create (uri, s)) {
353 public static XElement Load (TextReader tr)
355 return Load (tr, LoadOptions.None);
358 public static XElement Load (TextReader tr, LoadOptions options)
360 XmlReaderSettings s = new XmlReaderSettings ();
361 s.IgnoreWhitespace = (options & LoadOptions.PreserveWhitespace) == 0;
362 using (XmlReader r = XmlReader.Create (tr, s)) {
367 public static XElement Load (XmlReader reader)
369 return Load (reader, LoadOptions.None);
372 public static XElement Load (XmlReader reader, LoadOptions options)
374 XmlReaderSettings s = reader.Settings.Clone ();
375 s.IgnoreWhitespace = (options & LoadOptions.PreserveWhitespace) == 0;
376 using (XmlReader r = XmlReader.Create (reader, s)) {
381 static XElement LoadCore (XmlReader r)
384 if (r.NodeType != XmlNodeType.Element)
385 throw new InvalidOperationException ("The XmlReader must be positioned at an element");
386 XName name = XName.Get (r.LocalName, r.NamespaceURI);
387 XElement e = new XElement (name);
388 if (r.MoveToFirstAttribute ()) {
390 // not sure how current Orcas behavior makes sense here though ...
391 if (r.LocalName == "xmlns" && r.NamespaceURI == XNamespace.Xmlns.NamespaceName)
392 e.SetAttributeValue (XNamespace.None.GetName ("xmlns"), r.Value);
394 e.SetAttributeValue (XName.Get (r.LocalName, r.NamespaceURI), r.Value);
395 } while (r.MoveToNextAttribute ());
398 if (!r.IsEmptyElement) {
400 e.ReadContentFrom (r);
402 e.explicit_is_empty = false;
404 e.explicit_is_empty = true;
410 public static XElement Parse (string s)
412 return Parse (s, LoadOptions.None);
415 public static XElement Parse (string s, LoadOptions options)
417 return Load (new StringReader (s), options);
420 public void RemoveAll ()
426 public void RemoveAttributes ()
428 while (attr_first != null)
432 public void Save (string filename)
434 Save (filename, SaveOptions.None);
437 public void Save (string filename, SaveOptions options)
439 XmlWriterSettings s = new XmlWriterSettings ();
440 if ((options & SaveOptions.DisableFormatting) != 0) {
443 s.IndentChars = String.Empty;
444 s.NewLineChars = String.Empty;
446 using (XmlWriter w = XmlWriter.Create (filename)) {
451 public void Save (TextWriter tw)
453 Save (tw, SaveOptions.None);
456 public void Save (TextWriter tw, SaveOptions options)
458 XmlWriterSettings s = new XmlWriterSettings ();
459 if ((options & SaveOptions.DisableFormatting) != 0) {
462 s.IndentChars = String.Empty;
463 s.NewLineChars = String.Empty;
465 using (XmlWriter w = XmlWriter.Create (tw)) {
470 public void Save (XmlWriter w)
475 public IEnumerable <XElement> AncestorsAndSelf ()
477 return GetAncestorList (null, true);
480 public IEnumerable <XElement> AncestorsAndSelf (XName name)
482 return GetAncestorList (name, true);
485 public IEnumerable <XElement> DescendantsAndSelf ()
487 List <XElement> list = new List <XElement> ();
489 list.AddRange (Descendants ());
493 public IEnumerable <XElement> DescendantsAndSelf (XName name)
495 List <XElement> list = new List <XElement> ();
496 if (name == this.name)
498 list.AddRange (Descendants (name));
502 public IEnumerable <XNode> DescendantNodesAndSelf ()
505 foreach (XNode node in DescendantNodes ())
509 public void SetAttributeValue (XName name, object value)
511 XAttribute a = Attribute (name);
517 a = new XAttribute (name, value);
519 if (attr_first == null) {
523 attr_last.NextAttribute = a;
524 a.PreviousAttribute = attr_last;
529 a.Value = XUtil.ToString (value);
533 public override void WriteTo (XmlWriter w)
535 w.WriteStartElement (name.LocalName, name.Namespace.NamespaceName);
537 foreach (XAttribute a in Attributes ()) {
538 if (a.IsNamespaceDeclaration) {
539 if (a.Name.Namespace == XNamespace.Xmlns)
540 w.WriteAttributeString ("xmlns", a.Name.LocalName, XNamespace.Xmlns.NamespaceName, a.Value);
542 w.WriteAttributeString ("xmlns", a.Value);
545 w.WriteAttributeString (a.Name.LocalName, a.Name.Namespace.NamespaceName, a.Value);
548 foreach (XNode node in Nodes ())
551 if (explicit_is_empty)
552 w.WriteEndElement ();
554 w.WriteFullEndElement ();
557 public XNamespace GetDefaultNamespace ()
559 for (XElement el = this; el != null; el = el.Parent)
560 foreach (XAttribute a in el.Attributes ())
561 if (a.IsNamespaceDeclaration && a.Name.Namespace == XNamespace.None)
562 return XNamespace.Get (a.Value);
563 return XNamespace.None; // nothing is declared.
566 public XNamespace GetNamespaceOfPrefix (string prefix)
568 for (XElement el = this; el != null; el = el.Parent)
569 foreach (XAttribute a in el.Attributes ())
570 if (a.IsNamespaceDeclaration && a.Name.LocalName == prefix)
571 return XNamespace.Get (a.Value);
572 return XNamespace.None; // nothing is declared.
575 public string GetPrefixOfNamespace (XNamespace ns)
577 foreach (string prefix in GetPrefixOfNamespaceCore (ns))
578 if (GetNamespaceOfPrefix (prefix) == ns)
580 return null; // nothing is declared
583 IEnumerable<string> GetPrefixOfNamespaceCore (XNamespace ns)
585 for (XElement el = this; el != null; el = el.Parent)
586 foreach (XAttribute a in el.Attributes ())
587 if (a.IsNamespaceDeclaration && a.Value == ns.NamespaceName)
588 yield return a.Name.Namespace == XNamespace.None ? String.Empty : a.Name.LocalName;
591 public void ReplaceAll (object item)
597 public void ReplaceAll (params object [] items)
603 public void ReplaceAttributes (object item)
609 public void ReplaceAttributes (params object [] items)
615 public void SetElementValue (XName name, object value)
617 XElement el = new XElement (name, value);
622 public void SetValue (object value)
624 XNode n = XUtil.ToNode (value);
629 internal override void OnAdded (XNode node, bool addFirst)
631 if (node is XDocument || node is XDocumentType)
632 throw new ArgumentException (String.Format ("A node of type {0} cannot be added as a content", node.GetType ()));
635 void IXmlSerializable.WriteXml (XmlWriter writer)
640 void IXmlSerializable.ReadXml (XmlReader reader)
642 ReadContentFrom (reader);
645 XmlSchema IXmlSerializable.GetSchema ()