5 // Copyright 2007 Novell (http://www.novell.com)
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:
15 // The above copyright notice and this permission notice shall be
16 // included in all copies or substantial portions of the Software.
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.
28 using System.Collections;
29 using System.Collections.Generic;
33 using System.Xml.Schema;
34 using System.Xml.Serialization;
36 namespace System.Xml.Linq
38 public class XDocument : XContainer
46 public XDocument (params object [] content)
51 public XDocument (XDeclaration xmldecl, params object [] content)
53 Declaration = xmldecl;
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 {
70 foreach (object o in Nodes ())
71 if (o is XDocumentType)
72 return (XDocumentType) o;
77 public override XmlNodeType NodeType {
78 get { return XmlNodeType.Document; }
81 public XElement Root {
83 foreach (object o in Nodes ())
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 s.IgnoreWhitespace = (options & LoadOptions.PreserveWhitespace) == 0;
99 using (XmlReader r = XmlReader.Create (uri, s)) {
100 return LoadCore (r, options);
104 public static XDocument Load (Stream stream)
106 return Load (new StreamReader (stream), LoadOptions.None);
109 public static XDocument Load (Stream stream, LoadOptions options)
111 return Load (new StreamReader (stream), options);
114 public static XDocument Load (TextReader reader)
116 return Load (reader, LoadOptions.None);
119 public static XDocument Load (TextReader reader, LoadOptions options)
121 XmlReaderSettings s = new XmlReaderSettings ();
122 s.ProhibitDtd = false; // see XNodeNavigatorTest.MoveToId().
123 s.IgnoreWhitespace = (options & LoadOptions.PreserveWhitespace) == 0;
124 using (XmlReader r = XmlReader.Create (reader, s)) {
125 return LoadCore (r, options);
129 public static XDocument Load (XmlReader reader)
131 return Load (reader, LoadOptions.None);
134 public static XDocument Load (XmlReader reader, LoadOptions options)
136 XmlReaderSettings s = reader.Settings != null ? reader.Settings.Clone () : new XmlReaderSettings ();
137 s.IgnoreWhitespace = (options & LoadOptions.PreserveWhitespace) == 0;
138 using (XmlReader r = XmlReader.Create (reader, s)) {
139 return LoadCore (r, options);
143 static XDocument LoadCore (XmlReader reader, LoadOptions options)
145 XDocument doc = new XDocument ();
146 doc.ReadContent (reader, options);
150 void ReadContent (XmlReader reader, LoadOptions options)
152 if (reader.ReadState == ReadState.Initial)
154 if (reader.NodeType == XmlNodeType.XmlDeclaration) {
155 Declaration = new XDeclaration (
156 reader.GetAttribute ("version"),
157 reader.GetAttribute ("encoding"),
158 reader.GetAttribute ("standalone"));
161 ReadContentFrom (reader, options);
163 throw new InvalidOperationException ("The document element is missing.");
166 static void ValidateWhitespace (string s)
168 for (int i = 0; i < s.Length; i++)
170 case ' ': case '\t': case '\n': case '\r':
173 throw new ArgumentException ("Non-whitespace text appears directly in the document.");
177 public static XDocument Parse (string s)
179 return Parse (s, LoadOptions.None);
182 public static XDocument Parse (string s, LoadOptions options)
184 return Load (new StringReader (s), options);
187 public void Save (string filename)
189 Save (filename, SaveOptions.None);
192 public void Save (string filename, SaveOptions options)
194 XmlWriterSettings s = new XmlWriterSettings ();
195 if ((options & SaveOptions.DisableFormatting) == SaveOptions.None)
198 if ((options & SaveOptions.OmitDuplicateNamespaces) == SaveOptions.OmitDuplicateNamespaces)
199 s.NamespaceHandling |= NamespaceHandling.OmitDuplicates;
202 using (XmlWriter w = XmlWriter.Create (filename, s)) {
207 public void Save (TextWriter tw)
209 Save (tw, SaveOptions.None);
212 public void Save (TextWriter tw, SaveOptions options)
214 XmlWriterSettings s = new XmlWriterSettings ();
215 if ((options & SaveOptions.DisableFormatting) == SaveOptions.None)
218 if ((options & SaveOptions.OmitDuplicateNamespaces) == SaveOptions.OmitDuplicateNamespaces)
219 s.NamespaceHandling |= NamespaceHandling.OmitDuplicates;
221 using (XmlWriter w = XmlWriter.Create (tw, s)) {
226 public void Save (XmlWriter w)
231 public override void WriteTo (XmlWriter w)
233 if (xmldecl != null) {
234 if (xmldecl.Standalone != null)
235 w.WriteStartDocument (xmldecl.Standalone == "yes");
237 w.WriteStartDocument ();
239 foreach (XNode node in Nodes ())
243 internal override bool OnAddingObject (object obj, bool rejectAttribute, XNode refNode, bool addFirst)
245 VerifyAddedNode (obj, addFirst);
249 void VerifyAddedNode (object node, bool addFirst)
252 throw new InvalidOperationException ("Only a node is allowed here");
255 ValidateWhitespace ((string) node);
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");
264 else if (node is XElement) {
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");
272 public void Save (Stream stream)
274 Save (stream, SaveOptions.None);
277 public void Save (Stream stream, SaveOptions options)
279 XmlWriterSettings s = new XmlWriterSettings ();
280 if ((options & SaveOptions.DisableFormatting) == SaveOptions.None)
282 if ((options & SaveOptions.OmitDuplicateNamespaces) == SaveOptions.OmitDuplicateNamespaces)
283 s.NamespaceHandling |= NamespaceHandling.OmitDuplicates;
285 using (var writer = XmlWriter.Create (stream, s)){