d2abc59910f6d69a1ce6893230e58db3f87e7430
[mono.git] / mcs / class / System.Xml.Linq / System.Xml.Linq / XElement.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.Linq;
32 using System.Text;
33 using System.Xml;
34 using System.Xml.Schema;
35 using System.Xml.Serialization;
36
37 namespace System.Xml.Linq
38 {
39         [XmlSchemaProvider (null, IsAny = true)]
40         public class XElement : XContainer, IXmlSerializable
41         {
42                 static IEnumerable <XElement> emptySequence =
43                         new List <XElement> ();
44
45                 public static IEnumerable <XElement> EmptySequence {
46                         get { return emptySequence; }
47                 }
48
49                 XName name;
50                 XAttribute attr_first, attr_last;
51                 bool explicit_is_empty = true;
52
53                 public XElement (XName name, object content)
54                 {
55                         if (name == null)
56                                 throw new ArgumentNullException ("name");
57                         this.name = name;
58                         Add (content);
59                 }
60
61                 public XElement (XElement other)
62                 {
63                         if (other == null)
64                                 throw new ArgumentNullException ("other");
65                         name = other.name;
66                         Add (other.Attributes ());
67                         Add (other.Nodes ());
68                 }
69
70                 public XElement (XName name)
71                 {
72                         if (name == null)
73                                 throw new ArgumentNullException ("name");
74                         this.name = name;
75                 }
76
77                 public XElement (XName name, params object [] content)
78                 {
79                         if (name == null)
80                                 throw new ArgumentNullException ("name");
81                         this.name = name;
82                         Add (content);
83                 }
84
85                 public XElement (XStreamingElement other)
86                 {
87                         if (other == null)
88                                 throw new ArgumentNullException ("other");
89                         this.name = other.Name;
90                         Add (other.Contents);
91                 }
92
93                 [CLSCompliant (false)]
94                 public static explicit operator bool (XElement element)
95                 {
96                         if (element == null)
97                                 throw new ArgumentNullException ("element");
98                         return XUtil.ConvertToBoolean (element.Value);
99                 }
100
101                 [CLSCompliant (false)]
102                 public static explicit operator bool? (XElement element)
103                 {
104                         if (element == null)
105                                 return null;
106                         
107                         return element.Value == null ? (bool?) null : XUtil.ConvertToBoolean (element.Value);
108                 }
109
110                 [CLSCompliant (false)]
111                 public static explicit operator DateTime (XElement element)
112                 {
113                         if (element == null)
114                                 throw new ArgumentNullException ("element");
115                         return XUtil.ToDateTime (element.Value);
116                 }
117
118                 [CLSCompliant (false)]
119                 public static explicit operator DateTime? (XElement element)
120                 {
121                         if (element == null)
122                                 return null;
123                         
124                         return element.Value == null ? (DateTime?) null : XUtil.ToDateTime (element.Value);
125                 }
126
127 #if !TARGET_JVM // Same as for System.Xml.XmlConvert.ToDateTimeOffset
128
129                 [CLSCompliant (false)]
130                 public static explicit operator DateTimeOffset (XElement element)
131                 {
132                         if (element == null)
133                                 throw new ArgumentNullException ("element");
134                         return XmlConvert.ToDateTimeOffset (element.Value);
135                 }
136
137                 [CLSCompliant (false)]
138                 public static explicit operator DateTimeOffset? (XElement element)
139                 {
140                         if (element == null)
141                                 return null;
142                         
143                         return element.Value == null ? (DateTimeOffset?) null : XmlConvert.ToDateTimeOffset (element.Value);
144                 }
145
146 #endif
147
148                 [CLSCompliant (false)]
149                 public static explicit operator decimal (XElement element)
150                 {
151                         if (element == null)
152                                 throw new ArgumentNullException ("element");
153                         return XmlConvert.ToDecimal (element.Value);
154                 }
155
156                 [CLSCompliant (false)]
157                 public static explicit operator decimal? (XElement element)
158                 {
159                         if (element == null)
160                                 return null;
161                         
162                         return element.Value == null ? (decimal?) null : XmlConvert.ToDecimal (element.Value);
163                 }
164
165                 [CLSCompliant (false)]
166                 public static explicit operator double (XElement element)
167                 {
168                         if (element == null)
169                                 throw new ArgumentNullException ("element");
170                         return XmlConvert.ToDouble (element.Value);
171                 }
172
173                 [CLSCompliant (false)]
174                 public static explicit operator double? (XElement element)
175                 {
176                         if (element == null)
177                                 return null;
178                         
179                         return element.Value == null ? (double?) null : XmlConvert.ToDouble (element.Value);
180                 }
181
182                 [CLSCompliant (false)]
183                 public static explicit operator float (XElement element)
184                 {
185                         if (element == null)
186                                 throw new ArgumentNullException ("element");
187                         return XmlConvert.ToSingle (element.Value);
188                 }
189
190                 [CLSCompliant (false)]
191                 public static explicit operator float? (XElement element)
192                 {
193                         if (element == null)
194                                 return null;
195                         
196                         return element.Value == null ? (float?) null : XmlConvert.ToSingle (element.Value);
197                 }
198
199                 [CLSCompliant (false)]
200                 public static explicit operator Guid (XElement element)
201                 {
202                         if (element == null)
203                                 throw new ArgumentNullException ("element");
204                         return XmlConvert.ToGuid (element.Value);
205                 }
206
207                 [CLSCompliant (false)]
208                 public static explicit operator Guid? (XElement element)
209                 {
210                         if (element == null)
211                                 return null;
212                         
213                         return element.Value == null ? (Guid?) null : XmlConvert.ToGuid (element.Value);
214                 }
215
216                 [CLSCompliant (false)]
217                 public static explicit operator int (XElement element)
218                 {
219                         if (element == null)
220                                 throw new ArgumentNullException ("element");
221                         return XmlConvert.ToInt32 (element.Value);
222                 }
223
224                 [CLSCompliant (false)]
225                 public static explicit operator int? (XElement element)
226                 {
227                         if (element == null)
228                                 return null;
229                         
230                         return element.Value == null ? (int?) null : XmlConvert.ToInt32 (element.Value);
231                 }
232
233                 [CLSCompliant (false)]
234                 public static explicit operator long (XElement element)
235                 {
236                         if (element == null)
237                                 throw new ArgumentNullException ("element");
238                         return XmlConvert.ToInt64 (element.Value);
239                 }
240
241                 [CLSCompliant (false)]
242                 public static explicit operator long? (XElement element)
243                 {
244                         if (element == null)
245                                 return null;
246                         
247                         return element.Value == null ? (long?) null : XmlConvert.ToInt64 (element.Value);
248                 }
249
250                 [CLSCompliant (false)]
251                 public static explicit operator uint (XElement element)
252                 {
253                         if (element == null)
254                                 throw new ArgumentNullException ("element");
255                         return XmlConvert.ToUInt32 (element.Value);
256                 }
257
258                 [CLSCompliant (false)]
259                 public static explicit operator uint? (XElement element)
260                 {
261                         if (element == null)
262                                 return null;
263                         
264                         return element.Value == null ? (uint?) null : XmlConvert.ToUInt32 (element.Value);
265                 }
266
267                 [CLSCompliant (false)]
268                 public static explicit operator ulong (XElement element)
269                 {
270                         if (element == null)
271                                 throw new ArgumentNullException ("element");
272                         return XmlConvert.ToUInt64 (element.Value);
273                 }
274
275                 [CLSCompliant (false)]
276                 public static explicit operator ulong? (XElement element)
277                 {
278                         if (element == null)
279                                 return null;
280                         
281                         return element.Value == null ? (ulong?) null : XmlConvert.ToUInt64 (element.Value);
282                 }
283
284                 [CLSCompliant (false)]
285                 public static explicit operator TimeSpan (XElement element)
286                 {
287                         if (element == null)
288                                 throw new ArgumentNullException ("element");
289                         return XmlConvert.ToTimeSpan (element.Value);
290                 }
291
292                 [CLSCompliant (false)]
293                 public static explicit operator TimeSpan? (XElement element)
294                 {
295                         if (element == null)
296                                 return null;
297                         
298                         return element.Value == null ? (TimeSpan?) null : XmlConvert.ToTimeSpan (element.Value);
299                 }
300
301                 [CLSCompliant (false)]
302                 public static explicit operator string (XElement element)
303                 {
304                         if (element == null)
305                                 return null;
306                         
307                         return element.Value;
308                 }
309
310                 public XAttribute FirstAttribute {
311                         get { return attr_first; }
312                         internal set { attr_first = value; }
313                 }
314
315                 public XAttribute LastAttribute {
316                         get { return attr_last; }
317                         internal set { attr_last = value; }
318                 }
319
320                 public bool HasAttributes {
321                         get { return attr_first != null; }
322                 }
323
324                 public bool HasElements {
325                         get {
326                                 foreach (object o in Nodes ())
327                                         if (o is XElement)
328                                                 return true;
329                                 return false;
330                         }
331                 }
332
333                 public bool IsEmpty {
334                         get { return !Nodes ().GetEnumerator ().MoveNext () && explicit_is_empty; }
335                         internal set { explicit_is_empty = value; }
336                 }
337
338                 public XName Name {
339                         get { return name; }
340                         set {
341                                 if (value == null)
342                                         throw new ArgumentNullException ("Name");
343                                 OnNameChanging (this);
344                                 name = value;
345                                 OnNameChanged (this);
346                         }
347                 }
348
349                 public override XmlNodeType NodeType {
350                         get { return XmlNodeType.Element; }
351                 }
352
353                 public string Value {
354                         get {
355                                 StringBuilder sb = null;
356                                 foreach (XNode n in Nodes ()) {
357                                         if (sb == null)
358                                                 sb = new StringBuilder ();
359                                         if (n is XText)
360                                                 sb.Append (((XText) n).Value);
361                                         else if (n is XElement)
362                                                 sb.Append (((XElement) n).Value);
363                                 }
364                                 return sb == null ? String.Empty : sb.ToString ();
365                         }
366                         set {
367                                 RemoveNodes ();
368                                 Add (value);
369                         }
370                 }
371
372                 IEnumerable <XElement> GetAncestorList (XName name, bool getMeIn)
373                 {
374                         List <XElement> list = new List <XElement> ();
375                         if (getMeIn)
376                                 list.Add (this);
377                         for (XElement el = Parent as XElement; el != null; el = el.Parent as XElement)
378                                 if (name == null || el.Name == name)
379                                         list.Add (el);
380                         return list;
381                 }
382
383                 public XAttribute Attribute (XName name)
384                 {
385                         foreach (XAttribute a in Attributes ())
386                                 if (a.Name == name)
387                                         return a;
388                         return null;
389                 }
390
391                 public IEnumerable <XAttribute> Attributes ()
392                 {
393                         XAttribute next;
394                         for (XAttribute a = attr_first; a != null; a = next) {
395                                 next = a.NextAttribute;
396                                 yield return a;
397                         }
398                 }
399
400                 // huh?
401                 public IEnumerable <XAttribute> Attributes (XName name)
402                 {
403                         foreach (XAttribute a in Attributes ())
404                                 if (a.Name == name)
405                                         yield return a;
406                 }
407
408                 static void DefineDefaultSettings (XmlReaderSettings settings, LoadOptions options)
409                 {
410                         settings.ProhibitDtd = false;
411
412                         settings.IgnoreWhitespace = (options & LoadOptions.PreserveWhitespace) == 0;
413                 }
414
415                 static XmlReaderSettings CreateDefaultSettings (LoadOptions options)
416                 {
417                         var settings = new XmlReaderSettings ();
418                         DefineDefaultSettings (settings, options);
419                         return settings;
420                 }
421
422                 public static XElement Load (string uri)
423                 {
424                         return Load (uri, LoadOptions.None);
425                 }
426
427                 public static XElement Load (string uri, LoadOptions options)
428                 {
429                         XmlReaderSettings s = CreateDefaultSettings (options);
430
431                         using (XmlReader r = XmlReader.Create (uri, s)) {
432                                 return LoadCore (r, options);
433                         }
434                 }
435
436                 public static XElement Load (TextReader textReader)
437                 {
438                         return Load (textReader, LoadOptions.None);
439                 }
440
441                 public static XElement Load (TextReader textReader, LoadOptions options)
442                 {
443                         XmlReaderSettings s = CreateDefaultSettings (options);
444
445                         using (XmlReader r = XmlReader.Create (textReader, s)) {
446                                 return LoadCore (r, options);
447                         }
448                 }
449
450                 public static XElement Load (XmlReader reader)
451                 {
452                         return Load (reader, LoadOptions.None);
453                 }
454
455                 public static XElement Load (XmlReader reader, LoadOptions options)
456                 {
457                         XmlReaderSettings s = reader.Settings != null ? reader.Settings.Clone () : new XmlReaderSettings ();
458                         DefineDefaultSettings (s, options);
459
460                         using (XmlReader r = XmlReader.Create (reader, s)) {
461                                 return LoadCore (r, options);
462                         }
463                 }
464
465 #if MOBILE || NET_4_0
466                 public static XElement Load (Stream stream)
467                 {
468                         return Load (stream, LoadOptions.None);
469                 }
470
471                 public static XElement Load (Stream stream, LoadOptions options)
472                 {
473                         XmlReaderSettings s = new XmlReaderSettings ();
474                         DefineDefaultSettings (s, options);
475
476                         using (XmlReader r = XmlReader.Create (stream, s)) {
477                                 return LoadCore (r, options);
478                         }
479                 }
480 #endif
481
482                 internal static XElement LoadCore (XmlReader r, LoadOptions options)
483                 {
484                         r.MoveToContent ();
485                         if (r.NodeType != XmlNodeType.Element)
486                                 throw new InvalidOperationException ("The XmlReader must be positioned at an element");
487                         XName name = XName.Get (r.LocalName, r.NamespaceURI);
488                         XElement e = new XElement (name);
489                         e.FillLineInfoAndBaseUri (r, options);
490
491                         if (r.MoveToFirstAttribute ()) {
492                                 do {
493                                         // not sure how current Orcas behavior makes sense here though ...
494                                         if (r.LocalName == "xmlns" && r.NamespaceURI == XNamespace.Xmlns.NamespaceName)
495                                                 e.SetAttributeValue (XNamespace.None.GetName ("xmlns"), r.Value);
496                                         else
497                                                 e.SetAttributeValue (XName.Get (r.LocalName, r.NamespaceURI), r.Value);
498                                         e.LastAttribute.FillLineInfoAndBaseUri (r, options);
499                                 } while (r.MoveToNextAttribute ());
500                                 r.MoveToElement ();
501                         }
502                         if (!r.IsEmptyElement) {
503                                 r.Read ();
504                                 e.ReadContentFrom (r, options);
505                                 r.ReadEndElement ();
506                                 e.explicit_is_empty = false;
507                         } else {
508                                 e.explicit_is_empty = true;
509                                 r.Read ();
510                         }
511                         return e;
512                 }
513
514                 public static XElement Parse (string text)
515                 {
516                         return Parse (text, LoadOptions.None);
517                 }
518
519                 public static XElement Parse (string text, LoadOptions options)
520                 {
521                         return Load (new StringReader (text), options);
522                 }
523
524                 public void RemoveAll ()
525                 {
526                         RemoveAttributes ();
527                         RemoveNodes ();
528                 }
529
530                 public void RemoveAttributes ()
531                 {
532                         while (attr_first != null)
533                                 attr_last.Remove ();
534                 }
535
536                 public void Save (string fileName)
537                 {
538                         Save (fileName, SaveOptions.None);
539                 }
540
541                 public void Save (string fileName, SaveOptions options)
542                 {
543                         XmlWriterSettings s = new XmlWriterSettings ();
544
545                         if ((options & SaveOptions.DisableFormatting) == SaveOptions.None)
546                                 s.Indent = true;
547 #if NET_4_0 || MOBILE
548                         if ((options & SaveOptions.OmitDuplicateNamespaces) == SaveOptions.OmitDuplicateNamespaces)
549                                 s.NamespaceHandling |= NamespaceHandling.OmitDuplicates;
550 #endif
551                         using (XmlWriter w = XmlWriter.Create (fileName, s)) {
552                                 Save (w);
553                         }
554                 }
555
556                 public void Save (TextWriter textWriter)
557                 {
558                         Save (textWriter, SaveOptions.None);
559                 }
560
561                 public void Save (TextWriter textWriter, SaveOptions options)
562                 {
563                         XmlWriterSettings s = new XmlWriterSettings ();
564                         
565                         if ((options & SaveOptions.DisableFormatting) == SaveOptions.None)
566                                 s.Indent = true;
567 #if NET_4_0 || MOBILE
568                         if ((options & SaveOptions.OmitDuplicateNamespaces) == SaveOptions.OmitDuplicateNamespaces)
569                                 s.NamespaceHandling |= NamespaceHandling.OmitDuplicates;
570 #endif
571                         using (XmlWriter w = XmlWriter.Create (textWriter, s)) {
572                                 Save (w);
573                         }
574                 }
575
576                 public void Save (XmlWriter writer)
577                 {
578                         WriteTo (writer);
579                 }
580
581 #if NET_4_0 || MOBILE
582                 public void Save (Stream stream)
583                 {
584                         Save (stream, SaveOptions.None);
585                 }
586
587                 public void Save (Stream stream, SaveOptions options)
588                 {
589                         XmlWriterSettings s = new XmlWriterSettings ();
590                         if ((options & SaveOptions.DisableFormatting) == SaveOptions.None)
591                                 s.Indent = true;
592                         if ((options & SaveOptions.OmitDuplicateNamespaces) == SaveOptions.OmitDuplicateNamespaces)
593                                 s.NamespaceHandling |= NamespaceHandling.OmitDuplicates;
594
595                         using (var writer = XmlWriter.Create (stream, s)){
596                                 Save (writer);
597                         }
598                 }
599 #endif
600                 public IEnumerable <XElement> AncestorsAndSelf ()
601                 {
602                         return GetAncestorList (null, true);
603                 }
604
605                 public IEnumerable <XElement> AncestorsAndSelf (XName name)
606                 {
607                         return GetAncestorList (name, true);
608                 }
609
610                 public IEnumerable <XElement> DescendantsAndSelf ()
611                 {
612                         List <XElement> list = new List <XElement> ();
613                         list.Add (this);
614                         list.AddRange (Descendants ());
615                         return list;
616                 }
617
618                 public IEnumerable <XElement> DescendantsAndSelf (XName name)
619                 {
620                         List <XElement> list = new List <XElement> ();
621                         if (name == this.name)
622                                 list.Add (this);
623                         list.AddRange (Descendants (name));
624                         return list;
625                 }
626
627                 public IEnumerable <XNode> DescendantNodesAndSelf ()
628                 {
629                         yield return this;
630                         foreach (XNode node in DescendantNodes ())
631                                 yield return node;
632                 }
633
634                 public void SetAttributeValue (XName name, object value)
635                 {
636                         XAttribute a = Attribute (name);
637                         if (value == null) {
638                                 if (a != null)
639                                         a.Remove ();
640                         } else {
641                                 if (a == null) {
642                                         SetAttributeObject (new XAttribute (name, value));
643                                 }
644                                 else
645                                         a.Value = XUtil.ToString (value);
646                         }
647                 }
648
649                 void SetAttributeObject (XAttribute a)
650                 {
651                         OnAddingObject (a);
652                         a = (XAttribute) XUtil.GetDetachedObject (a);
653                         a.SetOwner (this);
654                         if (attr_first == null) {
655                                 attr_first = a;
656                                 attr_last = a;
657                         } else {
658                                 attr_last.NextAttribute = a;
659                                 a.PreviousAttribute = attr_last;
660                                 attr_last = a;
661                         }
662                         OnAddedObject (a);
663                 }
664
665                 string LookupPrefix (string ns, XmlWriter w)
666                 {
667                         string prefix = ns.Length > 0 ? GetPrefixOfNamespace (ns) ?? w.LookupPrefix (ns) : String.Empty;
668                         foreach (XAttribute a in Attributes ()) {
669                                 if (a.IsNamespaceDeclaration && a.Value == ns) {
670                                         if (a.Name.Namespace == XNamespace.Xmlns)
671                                                 prefix = a.Name.LocalName;
672                                         // otherwise xmlns="..."
673                                         break;
674                                 }
675                         }
676                         return prefix;
677                 }
678                 
679                 static string CreateDummyNamespace (ref int createdNS, IEnumerable<XAttribute> atts, bool isAttr)
680                 {
681                         if (!isAttr && atts.All (a => a.Name.LocalName != "xmlns" || a.Name.NamespaceName == XNamespace.Xmlns.NamespaceName))
682                                 return String.Empty;
683                         string p = null;
684                         do {
685                                 p = "p" + (++createdNS);
686                                 // check conflict
687                                 if (atts.All (a => a.Name.LocalName != p || a.Name.NamespaceName == XNamespace.Xmlns.NamespaceName))
688                                         break;
689                         } while (true);
690                         return p;
691                 }
692
693                 public override void WriteTo (XmlWriter writer)
694                 {
695                         // some people expect the same prefix output as in input,
696                         // in the loss of performance... see bug #466423.
697                         string prefix = LookupPrefix (name.NamespaceName, writer);
698                         int createdNS = 0;
699                         if (prefix == null)
700                                 prefix = CreateDummyNamespace (ref createdNS, Attributes (), false);
701
702                         writer.WriteStartElement (prefix, name.LocalName, name.Namespace.NamespaceName);
703
704                         foreach (XAttribute a in Attributes ()) {
705                                 if (a.IsNamespaceDeclaration) {
706                                         if (a.Name.Namespace == XNamespace.Xmlns)
707                                                 writer.WriteAttributeString ("xmlns", a.Name.LocalName, XNamespace.Xmlns.NamespaceName, a.Value);
708                                         else
709                                                 writer.WriteAttributeString ("xmlns", a.Value);
710                                 } else {
711                                         string apfix = LookupPrefix (a.Name.NamespaceName, writer);
712                                         if (apfix == null)
713                                                 apfix = CreateDummyNamespace (ref createdNS, Attributes (), true);
714                                         writer.WriteAttributeString (apfix, a.Name.LocalName, a.Name.Namespace.NamespaceName, a.Value);
715                                 }
716                         }
717
718                         foreach (XNode node in Nodes ())
719                                 node.WriteTo (writer);
720
721                         if (explicit_is_empty)
722                                 writer.WriteEndElement ();
723                         else
724                                 writer.WriteFullEndElement ();
725                 }
726
727                 public XNamespace GetDefaultNamespace ()
728                 {
729                         for (XElement el = this; el != null; el = el.Parent)
730                                 foreach (XAttribute a in el.Attributes ())
731                                         if (a.IsNamespaceDeclaration && a.Name.Namespace == XNamespace.None)
732                                                 return XNamespace.Get (a.Value);
733                         return XNamespace.None; // nothing is declared.
734                 }
735
736                 public XNamespace GetNamespaceOfPrefix (string prefix)
737                 {
738                         for (XElement el = this; el != null; el = el.Parent)
739                                 foreach (XAttribute a in el.Attributes ())
740                                         if (a.IsNamespaceDeclaration && (prefix.Length == 0 && a.Name.LocalName == "xmlns" || a.Name.LocalName == prefix))
741                                                 return XNamespace.Get (a.Value);
742                         return XNamespace.None; // nothing is declared.
743                 }
744
745                 public string GetPrefixOfNamespace (XNamespace ns)
746                 {
747                         foreach (string prefix in GetPrefixOfNamespaceCore (ns))
748                                 if (GetNamespaceOfPrefix (prefix) == ns)
749                                         return prefix;
750                         return null; // nothing is declared
751                 }
752                 
753                 IEnumerable<string> GetPrefixOfNamespaceCore (XNamespace ns)
754                 {
755                         for (XElement el = this; el != null; el = el.Parent)
756                                 foreach (XAttribute a in el.Attributes ())
757                                         if (a.IsNamespaceDeclaration && a.Value == ns.NamespaceName)
758                                                 yield return a.Name.Namespace == XNamespace.None ? String.Empty : a.Name.LocalName;
759                 }
760
761                 public void ReplaceAll (object content)
762                 {
763                         RemoveNodes ();
764                         Add (content);
765                 }
766
767                 public void ReplaceAll (params object [] content)
768                 {
769                         RemoveNodes ();
770                         Add (content);
771                 }
772
773                 public void ReplaceAttributes (object content)
774                 {
775                         RemoveAttributes ();
776                         Add (content);
777                 }
778
779                 public void ReplaceAttributes (params object [] content)
780                 {
781                         RemoveAttributes ();
782                         Add (content);
783                 }
784
785                 public void SetElementValue (XName name, object value)
786                 {
787                         var element = Element (name);
788                         if (element == null && value != null) {
789                                 Add (new XElement (name, value));
790                         } else if (element != null && value == null) {
791                                 element.Remove ();
792                         } else
793                                 element.SetValue (value);
794                 }
795
796                 public void SetValue (object value)
797                 {
798                         if (value == null)
799                                 throw new ArgumentNullException ("value");
800                         if (value is XAttribute || value is XDocument || value is XDeclaration || value is XDocumentType)
801                                 throw new ArgumentException (String.Format ("Node type {0} is not allowed as element value", value.GetType ()));
802                         RemoveNodes ();
803                         foreach (object o in XUtil.ExpandArray (value))
804                                 Add (o);
805                 }
806
807                 internal override bool OnAddingObject (object o, bool rejectAttribute, XNode refNode, bool addFirst)
808                 {
809                         if (o is XDocument || o is XDocumentType || o is XDeclaration || (rejectAttribute && o is XAttribute))
810                                 throw new ArgumentException (String.Format ("A node of type {0} cannot be added as a content", o.GetType ()));
811
812                         XAttribute a = o as XAttribute;
813                         if (a != null) {
814                                 foreach (XAttribute ia in Attributes ())
815                                         if (a.Name == ia.Name)
816                                                 throw new InvalidOperationException (String.Format ("Duplicate attribute: {0}", a.Name));
817                                 SetAttributeObject (a);
818                                 return true;
819                         }
820                         else if (o is string && refNode is XText) {
821                                 ((XText) refNode).Value += o as string;
822                                 return true;
823                         }
824                         else
825                                 return false;
826                 }
827
828                 void IXmlSerializable.WriteXml (XmlWriter writer)
829                 {
830                         Save (writer);
831                 }
832
833                 void IXmlSerializable.ReadXml (XmlReader reader)
834                 {
835                         ReadContentFrom (reader, LoadOptions.None);
836                 }
837
838                 XmlSchema IXmlSerializable.GetSchema ()
839                 {
840                         return null;
841                 }
842         }
843 }