Merge pull request #554 from deplinenoise/ppc_fixes
[mono.git] / mcs / class / System.Xml.Linq / System.Xml.Linq / XDocument.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         public class XDocument : XContainer
39         {
40                 XDeclaration xmldecl;
41
42                 public XDocument ()
43                 {
44                 }
45
46                 public XDocument (params object [] content)
47                 {
48                         Add (content);
49                 }
50
51                 public XDocument (XDeclaration declaration, params object [] content)
52                 {
53                         Declaration = declaration;
54                         Add (content);
55                 }
56
57                 public XDocument (XDocument other)
58                 {
59                         foreach (object o in other.Nodes ())
60                                 Add (XUtil.Clone (o));
61                 }
62
63                 public XDeclaration Declaration {
64                         get { return xmldecl; }
65                         set { xmldecl = value; }
66                 }
67
68                 public XDocumentType DocumentType {
69                         get {
70                                 foreach (object o in Nodes ())
71                                         if (o is XDocumentType)
72                                                 return (XDocumentType) o;
73                                 return null;
74                         }
75                 }
76
77                 public override XmlNodeType NodeType {
78                         get { return XmlNodeType.Document; }
79                 }
80
81                 public XElement Root {
82                         get {
83                                 foreach (object o in Nodes ())
84                                         if (o is XElement)
85                                                 return (XElement) o;
86                                 return null;
87                         }
88                 }
89
90                 public static XDocument Load (string uri)
91                 {
92                         return Load (uri, LoadOptions.None);
93                 }
94
95                 public static XDocument Load (string uri, LoadOptions options)
96                 {
97                         XmlReaderSettings s = new XmlReaderSettings ();
98                         s.ProhibitDtd = false; // see XNodeNavigatorTest.MoveToId().
99                         s.IgnoreWhitespace = (options & LoadOptions.PreserveWhitespace) == 0;
100                         using (XmlReader r = XmlReader.Create (uri, s)) {
101                                 return LoadCore (r, options);
102                         }
103                 }
104
105                 public static XDocument Load (Stream stream)
106                 {
107                         return Load (new StreamReader (stream), LoadOptions.None);
108                 }
109
110                 public static XDocument Load (Stream stream, LoadOptions options)
111                 {
112                         return Load (new StreamReader (stream), options);
113                 }
114
115                 public static XDocument Load (TextReader textReader)
116                 {
117                         return Load (textReader, LoadOptions.None);
118                 }
119
120                 public static XDocument Load (TextReader textReader, LoadOptions options)
121                 {
122                         XmlReaderSettings s = new XmlReaderSettings ();
123                         s.ProhibitDtd = false; // see XNodeNavigatorTest.MoveToId().
124                         s.IgnoreWhitespace = (options & LoadOptions.PreserveWhitespace) == 0;
125                         using (XmlReader r = XmlReader.Create (textReader, s)) {
126                                 return LoadCore (r, options);
127                         }
128                 }
129
130                 public static XDocument Load (XmlReader reader)
131                 {
132                         return Load (reader, LoadOptions.None);
133                 }
134
135                 public static XDocument Load (XmlReader reader, LoadOptions options)
136                 {
137                         XmlReaderSettings s = reader.Settings != null ? reader.Settings.Clone () : new XmlReaderSettings ();
138                         s.IgnoreWhitespace = (options & LoadOptions.PreserveWhitespace) == 0;
139                         using (XmlReader r = XmlReader.Create (reader, s)) {
140                                 return LoadCore (r, options);
141                         }
142                 }
143
144                 static XDocument LoadCore (XmlReader reader, LoadOptions options)
145                 {
146                         XDocument doc = new XDocument ();
147                         doc.ReadContent (reader, options);
148                         return doc;
149                 }
150
151                 void ReadContent (XmlReader reader, LoadOptions options)
152                 {
153                         if (reader.ReadState == ReadState.Initial)
154                                 reader.Read ();
155                         this.FillLineInfoAndBaseUri (reader, options);
156                         if (reader.NodeType == XmlNodeType.XmlDeclaration) {
157                                 Declaration = new XDeclaration (
158                                         reader.GetAttribute ("version"),
159                                         reader.GetAttribute ("encoding"),
160                                         reader.GetAttribute ("standalone"));
161                                 reader.Read ();
162                         }
163                         ReadContentFrom (reader, options);
164                         if (Root == null)
165                                 throw new InvalidOperationException ("The document element is missing.");
166                 }
167
168                 static void ValidateWhitespace (string s)
169                 {
170                         for (int i = 0; i < s.Length; i++)
171                                 switch (s [i]) {
172                                 case ' ': case '\t': case '\n': case '\r':
173                                         continue;
174                                 default:
175                                         throw new ArgumentException ("Non-whitespace text appears directly in the document.");
176                                 }
177                 }
178
179                 public static XDocument Parse (string text)
180                 {
181                         return Parse (text, LoadOptions.None);
182                 }
183
184                 public static XDocument Parse (string text, LoadOptions options)
185                 {
186                         return Load (new StringReader (text), options);
187                 }
188
189                 public void Save (string fileName)
190                 {
191                         Save (fileName, SaveOptions.None);
192                 }
193
194                 public void Save (string fileName, SaveOptions options)
195                 {
196                         XmlWriterSettings s = new XmlWriterSettings ();
197                         if ((options & SaveOptions.DisableFormatting) == SaveOptions.None)
198                                 s.Indent = true;
199 #if NET_4_0
200                         if ((options & SaveOptions.OmitDuplicateNamespaces) == SaveOptions.OmitDuplicateNamespaces)
201                                 s.NamespaceHandling |= NamespaceHandling.OmitDuplicates;
202 #endif
203                         
204                         using (XmlWriter w = XmlWriter.Create (fileName, s)) {
205                                 Save (w);
206                         }
207                 }
208
209                 public void Save (TextWriter textWriter)
210                 {
211                         Save (textWriter, SaveOptions.None);
212                 }
213
214                 public void Save (TextWriter textWriter, SaveOptions options)
215                 {
216                         XmlWriterSettings s = new XmlWriterSettings ();
217                         if ((options & SaveOptions.DisableFormatting) == SaveOptions.None)
218                                 s.Indent = true;
219 #if NET_4_0
220                         if ((options & SaveOptions.OmitDuplicateNamespaces) == SaveOptions.OmitDuplicateNamespaces)
221                                 s.NamespaceHandling |= NamespaceHandling.OmitDuplicates;
222 #endif
223                         using (XmlWriter w = XmlWriter.Create (textWriter, s)) {
224                                 Save (w);
225                         }
226                 }
227
228                 public void Save (XmlWriter writer)
229                 {
230                         WriteTo (writer);
231                 }
232
233                 public override void WriteTo (XmlWriter writer)
234                 {
235                         if (xmldecl != null && xmldecl.Standalone != null)
236                                 writer.WriteStartDocument (xmldecl.Standalone == "yes");
237                         else
238                                 writer.WriteStartDocument ();
239                         foreach (XNode node in Nodes ())
240                                 node.WriteTo (writer);
241                 }
242
243                 internal override bool OnAddingObject (object obj, bool rejectAttribute, XNode refNode, bool addFirst)
244                 {
245                         VerifyAddedNode (obj, addFirst);
246                         return false;
247                 }
248
249                 void VerifyAddedNode (object node, bool addFirst)
250                 {
251                         if (node == null)
252                                 throw new InvalidOperationException ("Only a node is allowed here");
253
254                         if (node is string)
255                                 ValidateWhitespace ((string) node);
256                         if (node is XText)
257                                 ValidateWhitespace (((XText) node).Value);
258                         else if (node is XDocumentType) {
259                                 if (DocumentType != null)
260                                         throw new InvalidOperationException ("There already is another document type declaration");
261                                 if (Root != null && !addFirst)
262                                         throw new InvalidOperationException ("A document type cannot be added after the document element");
263                         }
264                         else if (node is XElement) {
265                                 if (Root != null)
266                                         throw new InvalidOperationException ("There already is another document element");
267                                 if (DocumentType != null && addFirst)
268                                         throw new InvalidOperationException ("An element cannot be added before the document type declaration");
269                         }
270                 }
271 #if NET_4_0
272                 public void Save (Stream stream)
273                 {
274                         Save (stream, SaveOptions.None);
275                 }
276
277                 public void Save (Stream stream, SaveOptions options)
278                 {
279                         XmlWriterSettings s = new XmlWriterSettings ();
280                         if ((options & SaveOptions.DisableFormatting) == SaveOptions.None)
281                                 s.Indent = true;
282                         if ((options & SaveOptions.OmitDuplicateNamespaces) == SaveOptions.OmitDuplicateNamespaces)
283                                 s.NamespaceHandling |= NamespaceHandling.OmitDuplicates;
284         
285                         using (var writer = XmlWriter.Create (stream, s)){
286                                 Save (writer);
287                         }
288                 }
289
290 #endif
291         }
292 }