Add Xml declaration even for such document that lacks XDeclaration.
[mono-project.git] / mcs / class / System.Xml.Linq / System.Xml.Linq / XDocument.cs
blobea785e9168e03e91c0716637a08835f58d50bc07
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.
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;
36 namespace System.Xml.Linq
38 public class XDocument : XContainer
40 XDeclaration xmldecl;
42 public XDocument ()
46 public XDocument (params object [] content)
48 Add (content);
51 public XDocument (XDeclaration xmldecl, params object [] content)
53 Declaration = xmldecl;
54 Add (content);
57 public XDocument (XDocument other)
59 foreach (object o in other.Nodes ())
60 Add (XUtil.Clone (o));
63 public XDeclaration Declaration {
64 get { return xmldecl; }
65 set { xmldecl = value; }
68 public XDocumentType DocumentType {
69 get {
70 foreach (object o in Nodes ())
71 if (o is XDocumentType)
72 return (XDocumentType) o;
73 return null;
77 public override XmlNodeType NodeType {
78 get { return XmlNodeType.Document; }
81 public XElement Root {
82 get {
83 foreach (object o in Nodes ())
84 if (o is XElement)
85 return (XElement) o;
86 return null;
90 public static XDocument Load (string uri)
92 return Load (uri, LoadOptions.None);
95 public static XDocument Load (string uri, LoadOptions options)
97 XmlReaderSettings s = new XmlReaderSettings ();
98 #if !MOONLIGHT
99 s.ProhibitDtd = false; // see XNodeNavigatorTest.MoveToId().
100 #endif
101 s.IgnoreWhitespace = (options & LoadOptions.PreserveWhitespace) == 0;
102 using (XmlReader r = XmlReader.Create (uri, s)) {
103 return LoadCore (r, options);
107 public static XDocument Load (Stream stream)
109 return Load (new StreamReader (stream), LoadOptions.None);
112 public static XDocument Load (Stream stream, LoadOptions options)
114 return Load (new StreamReader (stream), options);
117 public static XDocument Load (TextReader reader)
119 return Load (reader, LoadOptions.None);
122 public static XDocument Load (TextReader reader, LoadOptions options)
124 XmlReaderSettings s = new XmlReaderSettings ();
125 #if !MOONLIGHT
126 s.ProhibitDtd = false; // see XNodeNavigatorTest.MoveToId().
127 #endif
128 s.IgnoreWhitespace = (options & LoadOptions.PreserveWhitespace) == 0;
129 using (XmlReader r = XmlReader.Create (reader, s)) {
130 return LoadCore (r, options);
134 public static XDocument Load (XmlReader reader)
136 return Load (reader, LoadOptions.None);
139 public static XDocument Load (XmlReader reader, LoadOptions options)
141 XmlReaderSettings s = reader.Settings != null ? reader.Settings.Clone () : new XmlReaderSettings ();
142 s.IgnoreWhitespace = (options & LoadOptions.PreserveWhitespace) == 0;
143 using (XmlReader r = XmlReader.Create (reader, s)) {
144 return LoadCore (r, options);
148 static XDocument LoadCore (XmlReader reader, LoadOptions options)
150 XDocument doc = new XDocument ();
151 doc.ReadContent (reader, options);
152 return doc;
155 void ReadContent (XmlReader reader, LoadOptions options)
157 if (reader.ReadState == ReadState.Initial)
158 reader.Read ();
159 this.FillLineInfoAndBaseUri (reader, options);
160 if (reader.NodeType == XmlNodeType.XmlDeclaration) {
161 Declaration = new XDeclaration (
162 reader.GetAttribute ("version"),
163 reader.GetAttribute ("encoding"),
164 reader.GetAttribute ("standalone"));
165 reader.Read ();
167 ReadContentFrom (reader, options);
168 if (Root == null)
169 throw new InvalidOperationException ("The document element is missing.");
172 static void ValidateWhitespace (string s)
174 for (int i = 0; i < s.Length; i++)
175 switch (s [i]) {
176 case ' ': case '\t': case '\n': case '\r':
177 continue;
178 default:
179 throw new ArgumentException ("Non-whitespace text appears directly in the document.");
183 public static XDocument Parse (string s)
185 return Parse (s, LoadOptions.None);
188 public static XDocument Parse (string s, LoadOptions options)
190 return Load (new StringReader (s), options);
193 public void Save (string filename)
195 Save (filename, SaveOptions.None);
198 public void Save (string filename, SaveOptions options)
200 XmlWriterSettings s = new XmlWriterSettings ();
201 if ((options & SaveOptions.DisableFormatting) == SaveOptions.None)
202 s.Indent = true;
203 #if NET_4_0
204 if ((options & SaveOptions.OmitDuplicateNamespaces) == SaveOptions.OmitDuplicateNamespaces)
205 s.NamespaceHandling |= NamespaceHandling.OmitDuplicates;
206 #endif
208 using (XmlWriter w = XmlWriter.Create (filename, s)) {
209 Save (w);
213 public void Save (TextWriter tw)
215 Save (tw, SaveOptions.None);
218 public void Save (TextWriter tw, SaveOptions options)
220 XmlWriterSettings s = new XmlWriterSettings ();
221 if ((options & SaveOptions.DisableFormatting) == SaveOptions.None)
222 s.Indent = true;
223 #if NET_4_0
224 if ((options & SaveOptions.OmitDuplicateNamespaces) == SaveOptions.OmitDuplicateNamespaces)
225 s.NamespaceHandling |= NamespaceHandling.OmitDuplicates;
226 #endif
227 using (XmlWriter w = XmlWriter.Create (tw, s)) {
228 Save (w);
232 public void Save (XmlWriter w)
234 WriteTo (w);
237 public override void WriteTo (XmlWriter w)
239 if (xmldecl != null && xmldecl.Standalone != null)
240 w.WriteStartDocument (xmldecl.Standalone == "yes");
241 else
242 w.WriteStartDocument ();
243 foreach (XNode node in Nodes ())
244 node.WriteTo (w);
247 internal override bool OnAddingObject (object obj, bool rejectAttribute, XNode refNode, bool addFirst)
249 VerifyAddedNode (obj, addFirst);
250 return false;
253 void VerifyAddedNode (object node, bool addFirst)
255 if (node == null)
256 throw new InvalidOperationException ("Only a node is allowed here");
258 if (node is string)
259 ValidateWhitespace ((string) node);
260 if (node is XText)
261 ValidateWhitespace (((XText) node).Value);
262 else if (node is XDocumentType) {
263 if (DocumentType != null)
264 throw new InvalidOperationException ("There already is another document type declaration");
265 if (Root != null && !addFirst)
266 throw new InvalidOperationException ("A document type cannot be added after the document element");
268 else if (node is XElement) {
269 if (Root != null)
270 throw new InvalidOperationException ("There already is another document element");
271 if (DocumentType != null && addFirst)
272 throw new InvalidOperationException ("An element cannot be added before the document type declaration");
275 #if NET_4_0
276 public void Save (Stream stream)
278 Save (stream, SaveOptions.None);
281 public void Save (Stream stream, SaveOptions options)
283 XmlWriterSettings s = new XmlWriterSettings ();
284 if ((options & SaveOptions.DisableFormatting) == SaveOptions.None)
285 s.Indent = true;
286 if ((options & SaveOptions.OmitDuplicateNamespaces) == SaveOptions.OmitDuplicateNamespaces)
287 s.NamespaceHandling |= NamespaceHandling.OmitDuplicates;
289 using (var writer = XmlWriter.Create (stream, s)){
290 Save (writer);
294 #endif