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