Merge pull request #409 from Alkarex/patch-1
[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 #if MOONLIGHT
411                         // 2.1 has a DtdProcessing property which defaults to DtdProcessing.Prohibit
412                         settings.DtdProcessing = DtdProcessing.Parse;
413 #else
414                         settings.ProhibitDtd = false;
415 #endif
416
417                         settings.IgnoreWhitespace = (options & LoadOptions.PreserveWhitespace) == 0;
418                 }
419
420                 static XmlReaderSettings CreateDefaultSettings (LoadOptions options)
421                 {
422                         var settings = new XmlReaderSettings ();
423                         DefineDefaultSettings (settings, options);
424                         return settings;
425                 }
426
427                 public static XElement Load (string uri)
428                 {
429                         return Load (uri, LoadOptions.None);
430                 }
431
432                 public static XElement Load (string uri, LoadOptions options)
433                 {
434                         XmlReaderSettings s = CreateDefaultSettings (options);
435
436                         using (XmlReader r = XmlReader.Create (uri, s)) {
437                                 return LoadCore (r, options);
438                         }
439                 }
440
441                 public static XElement Load (TextReader textReader)
442                 {
443                         return Load (textReader, LoadOptions.None);
444                 }
445
446                 public static XElement Load (TextReader textReader, LoadOptions options)
447                 {
448                         XmlReaderSettings s = CreateDefaultSettings (options);
449
450                         using (XmlReader r = XmlReader.Create (textReader, s)) {
451                                 return LoadCore (r, options);
452                         }
453                 }
454
455                 public static XElement Load (XmlReader reader)
456                 {
457                         return Load (reader, LoadOptions.None);
458                 }
459
460                 public static XElement Load (XmlReader reader, LoadOptions options)
461                 {
462                         XmlReaderSettings s = reader.Settings != null ? reader.Settings.Clone () : new XmlReaderSettings ();
463                         DefineDefaultSettings (s, options);
464
465                         using (XmlReader r = XmlReader.Create (reader, s)) {
466                                 return LoadCore (r, options);
467                         }
468                 }
469
470 #if MOONLIGHT || MOBILE || NET_4_0
471                 public static XElement Load (Stream stream)
472                 {
473                         return Load (stream, LoadOptions.None);
474                 }
475
476                 public static XElement Load (Stream stream, LoadOptions options)
477                 {
478                         XmlReaderSettings s = new XmlReaderSettings ();
479                         DefineDefaultSettings (s, options);
480
481                         using (XmlReader r = XmlReader.Create (stream, s)) {
482                                 return LoadCore (r, options);
483                         }
484                 }
485 #endif
486
487                 internal static XElement LoadCore (XmlReader r, LoadOptions options)
488                 {
489                         r.MoveToContent ();
490                         if (r.NodeType != XmlNodeType.Element)
491                                 throw new InvalidOperationException ("The XmlReader must be positioned at an element");
492                         XName name = XName.Get (r.LocalName, r.NamespaceURI);
493                         XElement e = new XElement (name);
494                         e.FillLineInfoAndBaseUri (r, options);
495
496                         if (r.MoveToFirstAttribute ()) {
497                                 do {
498                                         // not sure how current Orcas behavior makes sense here though ...
499                                         if (r.LocalName == "xmlns" && r.NamespaceURI == XNamespace.Xmlns.NamespaceName)
500                                                 e.SetAttributeValue (XNamespace.None.GetName ("xmlns"), r.Value);
501                                         else
502                                                 e.SetAttributeValue (XName.Get (r.LocalName, r.NamespaceURI), r.Value);
503                                         e.LastAttribute.FillLineInfoAndBaseUri (r, options);
504                                 } while (r.MoveToNextAttribute ());
505                                 r.MoveToElement ();
506                         }
507                         if (!r.IsEmptyElement) {
508                                 r.Read ();
509                                 e.ReadContentFrom (r, options);
510                                 r.ReadEndElement ();
511                                 e.explicit_is_empty = false;
512                         } else {
513                                 e.explicit_is_empty = true;
514                                 r.Read ();
515                         }
516                         return e;
517                 }
518
519                 public static XElement Parse (string text)
520                 {
521                         return Parse (text, LoadOptions.None);
522                 }
523
524                 public static XElement Parse (string text, LoadOptions options)
525                 {
526                         return Load (new StringReader (text), options);
527                 }
528
529                 public void RemoveAll ()
530                 {
531                         RemoveAttributes ();
532                         RemoveNodes ();
533                 }
534
535                 public void RemoveAttributes ()
536                 {
537                         while (attr_first != null)
538                                 attr_last.Remove ();
539                 }
540
541                 public void Save (string fileName)
542                 {
543                         Save (fileName, SaveOptions.None);
544                 }
545
546                 public void Save (string fileName, SaveOptions options)
547                 {
548                         XmlWriterSettings s = new XmlWriterSettings ();
549
550                         if ((options & SaveOptions.DisableFormatting) == SaveOptions.None)
551                                 s.Indent = true;
552 #if NET_4_0 || MOONLIGHT || MOBILE
553                         if ((options & SaveOptions.OmitDuplicateNamespaces) == SaveOptions.OmitDuplicateNamespaces)
554                                 s.NamespaceHandling |= NamespaceHandling.OmitDuplicates;
555 #endif
556                         using (XmlWriter w = XmlWriter.Create (fileName, s)) {
557                                 Save (w);
558                         }
559                 }
560
561                 public void Save (TextWriter textWriter)
562                 {
563                         Save (textWriter, SaveOptions.None);
564                 }
565
566                 public void Save (TextWriter textWriter, SaveOptions options)
567                 {
568                         XmlWriterSettings s = new XmlWriterSettings ();
569                         
570                         if ((options & SaveOptions.DisableFormatting) == SaveOptions.None)
571                                 s.Indent = true;
572 #if NET_4_0 || MOONLIGHT || MOBILE
573                         if ((options & SaveOptions.OmitDuplicateNamespaces) == SaveOptions.OmitDuplicateNamespaces)
574                                 s.NamespaceHandling |= NamespaceHandling.OmitDuplicates;
575 #endif
576                         using (XmlWriter w = XmlWriter.Create (textWriter, s)) {
577                                 Save (w);
578                         }
579                 }
580
581                 public void Save (XmlWriter writer)
582                 {
583                         WriteTo (writer);
584                 }
585
586 #if NET_4_0 || MOONLIGHT || MOBILE
587                 public void Save (Stream stream)
588                 {
589                         Save (stream, SaveOptions.None);
590                 }
591
592                 public void Save (Stream stream, SaveOptions options)
593                 {
594                         XmlWriterSettings s = new XmlWriterSettings ();
595                         if ((options & SaveOptions.DisableFormatting) == SaveOptions.None)
596                                 s.Indent = true;
597                         if ((options & SaveOptions.OmitDuplicateNamespaces) == SaveOptions.OmitDuplicateNamespaces)
598                                 s.NamespaceHandling |= NamespaceHandling.OmitDuplicates;
599
600                         using (var writer = XmlWriter.Create (stream, s)){
601                                 Save (writer);
602                         }
603                 }
604 #endif
605                 public IEnumerable <XElement> AncestorsAndSelf ()
606                 {
607                         return GetAncestorList (null, true);
608                 }
609
610                 public IEnumerable <XElement> AncestorsAndSelf (XName name)
611                 {
612                         return GetAncestorList (name, true);
613                 }
614
615                 public IEnumerable <XElement> DescendantsAndSelf ()
616                 {
617                         List <XElement> list = new List <XElement> ();
618                         list.Add (this);
619                         list.AddRange (Descendants ());
620                         return list;
621                 }
622
623                 public IEnumerable <XElement> DescendantsAndSelf (XName name)
624                 {
625                         List <XElement> list = new List <XElement> ();
626                         if (name == this.name)
627                                 list.Add (this);
628                         list.AddRange (Descendants (name));
629                         return list;
630                 }
631
632                 public IEnumerable <XNode> DescendantNodesAndSelf ()
633                 {
634                         yield return this;
635                         foreach (XNode node in DescendantNodes ())
636                                 yield return node;
637                 }
638
639                 public void SetAttributeValue (XName name, object value)
640                 {
641                         XAttribute a = Attribute (name);
642                         if (value == null) {
643                                 if (a != null)
644                                         a.Remove ();
645                         } else {
646                                 if (a == null) {
647                                         SetAttributeObject (new XAttribute (name, value));
648                                 }
649                                 else
650                                         a.Value = XUtil.ToString (value);
651                         }
652                 }
653
654                 void SetAttributeObject (XAttribute a)
655                 {
656                         OnAddingObject (a);
657                         a = (XAttribute) XUtil.GetDetachedObject (a);
658                         a.SetOwner (this);
659                         if (attr_first == null) {
660                                 attr_first = a;
661                                 attr_last = a;
662                         } else {
663                                 attr_last.NextAttribute = a;
664                                 a.PreviousAttribute = attr_last;
665                                 attr_last = a;
666                         }
667                         OnAddedObject (a);
668                 }
669
670                 string LookupPrefix (string ns, XmlWriter w)
671                 {
672                         string prefix = ns.Length > 0 ? GetPrefixOfNamespace (ns) ?? w.LookupPrefix (ns) : String.Empty;
673                         foreach (XAttribute a in Attributes ()) {
674                                 if (a.IsNamespaceDeclaration && a.Value == ns) {
675                                         if (a.Name.Namespace == XNamespace.Xmlns)
676                                                 prefix = a.Name.LocalName;
677                                         // otherwise xmlns="..."
678                                         break;
679                                 }
680                         }
681                         return prefix;
682                 }
683                 
684                 static string CreateDummyNamespace (ref int createdNS, IEnumerable<XAttribute> atts, bool isAttr)
685                 {
686                         if (!isAttr && atts.All (a => a.Name.LocalName != "xmlns" || a.Name.NamespaceName == XNamespace.Xmlns.NamespaceName))
687                                 return String.Empty;
688                         string p = null;
689                         do {
690                                 p = "p" + (++createdNS);
691                                 // check conflict
692                                 if (atts.All (a => a.Name.LocalName != p || a.Name.NamespaceName == XNamespace.Xmlns.NamespaceName))
693                                         break;
694                         } while (true);
695                         return p;
696                 }
697
698                 public override void WriteTo (XmlWriter writer)
699                 {
700                         // some people expect the same prefix output as in input,
701                         // in the loss of performance... see bug #466423.
702                         string prefix = LookupPrefix (name.NamespaceName, writer);
703                         int createdNS = 0;
704                         if (prefix == null)
705                                 prefix = CreateDummyNamespace (ref createdNS, Attributes (), false);
706
707                         writer.WriteStartElement (prefix, name.LocalName, name.Namespace.NamespaceName);
708
709                         foreach (XAttribute a in Attributes ()) {
710                                 if (a.IsNamespaceDeclaration) {
711                                         if (a.Name.Namespace == XNamespace.Xmlns)
712                                                 writer.WriteAttributeString ("xmlns", a.Name.LocalName, XNamespace.Xmlns.NamespaceName, a.Value);
713                                         else
714                                                 writer.WriteAttributeString ("xmlns", a.Value);
715                                 } else {
716                                         string apfix = LookupPrefix (a.Name.NamespaceName, writer);
717                                         if (apfix == null)
718                                                 apfix = CreateDummyNamespace (ref createdNS, Attributes (), true);
719                                         writer.WriteAttributeString (apfix, a.Name.LocalName, a.Name.Namespace.NamespaceName, a.Value);
720                                 }
721                         }
722
723                         foreach (XNode node in Nodes ())
724                                 node.WriteTo (writer);
725
726                         if (explicit_is_empty)
727                                 writer.WriteEndElement ();
728                         else
729                                 writer.WriteFullEndElement ();
730                 }
731
732                 public XNamespace GetDefaultNamespace ()
733                 {
734                         for (XElement el = this; el != null; el = el.Parent)
735                                 foreach (XAttribute a in el.Attributes ())
736                                         if (a.IsNamespaceDeclaration && a.Name.Namespace == XNamespace.None)
737                                                 return XNamespace.Get (a.Value);
738                         return XNamespace.None; // nothing is declared.
739                 }
740
741                 public XNamespace GetNamespaceOfPrefix (string prefix)
742                 {
743                         for (XElement el = this; el != null; el = el.Parent)
744                                 foreach (XAttribute a in el.Attributes ())
745                                         if (a.IsNamespaceDeclaration && (prefix.Length == 0 && a.Name.LocalName == "xmlns" || a.Name.LocalName == prefix))
746                                                 return XNamespace.Get (a.Value);
747                         return XNamespace.None; // nothing is declared.
748                 }
749
750                 public string GetPrefixOfNamespace (XNamespace ns)
751                 {
752                         foreach (string prefix in GetPrefixOfNamespaceCore (ns))
753                                 if (GetNamespaceOfPrefix (prefix) == ns)
754                                         return prefix;
755                         return null; // nothing is declared
756                 }
757                 
758                 IEnumerable<string> GetPrefixOfNamespaceCore (XNamespace ns)
759                 {
760                         for (XElement el = this; el != null; el = el.Parent)
761                                 foreach (XAttribute a in el.Attributes ())
762                                         if (a.IsNamespaceDeclaration && a.Value == ns.NamespaceName)
763                                                 yield return a.Name.Namespace == XNamespace.None ? String.Empty : a.Name.LocalName;
764                 }
765
766                 public void ReplaceAll (object content)
767                 {
768                         RemoveNodes ();
769                         Add (content);
770                 }
771
772                 public void ReplaceAll (params object [] content)
773                 {
774                         RemoveNodes ();
775                         Add (content);
776                 }
777
778                 public void ReplaceAttributes (object content)
779                 {
780                         RemoveAttributes ();
781                         Add (content);
782                 }
783
784                 public void ReplaceAttributes (params object [] content)
785                 {
786                         RemoveAttributes ();
787                         Add (content);
788                 }
789
790                 public void SetElementValue (XName name, object value)
791                 {
792                         var element = Element (name);
793                         if (element == null && value != null) {
794                                 Add (new XElement (name, value));
795                         } else if (element != null && value == null) {
796                                 element.Remove ();
797                         } else
798                                 element.SetValue (value);
799                 }
800
801                 public void SetValue (object value)
802                 {
803                         if (value == null)
804                                 throw new ArgumentNullException ("value");
805                         if (value is XAttribute || value is XDocument || value is XDeclaration || value is XDocumentType)
806                                 throw new ArgumentException (String.Format ("Node type {0} is not allowed as element value", value.GetType ()));
807                         RemoveNodes ();
808                         foreach (object o in XUtil.ExpandArray (value))
809                                 Add (o);
810                 }
811
812                 internal override bool OnAddingObject (object o, bool rejectAttribute, XNode refNode, bool addFirst)
813                 {
814                         if (o is XDocument || o is XDocumentType || o is XDeclaration || (rejectAttribute && o is XAttribute))
815                                 throw new ArgumentException (String.Format ("A node of type {0} cannot be added as a content", o.GetType ()));
816
817                         XAttribute a = o as XAttribute;
818                         if (a != null) {
819                                 foreach (XAttribute ia in Attributes ())
820                                         if (a.Name == ia.Name)
821                                                 throw new InvalidOperationException (String.Format ("Duplicate attribute: {0}", a.Name));
822                                 SetAttributeObject (a);
823                                 return true;
824                         }
825                         else if (o is string && refNode is XText) {
826                                 ((XText) refNode).Value += o as string;
827                                 return true;
828                         }
829                         else
830                                 return false;
831                 }
832
833                 void IXmlSerializable.WriteXml (XmlWriter writer)
834                 {
835                         Save (writer);
836                 }
837
838                 void IXmlSerializable.ReadXml (XmlReader reader)
839                 {
840                         ReadContentFrom (reader, LoadOptions.None);
841                 }
842
843                 XmlSchema IXmlSerializable.GetSchema ()
844                 {
845                         return null;
846                 }
847         }
848 }