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 ();
99 s
.ProhibitDtd
= false; // see XNodeNavigatorTest.MoveToId().
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 ();
126 s
.ProhibitDtd
= false; // see XNodeNavigatorTest.MoveToId().
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
);
155 void ReadContent (XmlReader reader
, LoadOptions options
)
157 if (reader
.ReadState
== ReadState
.Initial
)
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"));
167 ReadContentFrom (reader
, options
);
169 throw new InvalidOperationException ("The document element is missing.");
172 static void ValidateWhitespace (string s
)
174 for (int i
= 0; i
< s
.Length
; i
++)
176 case ' ': case '\t': case '\n': case '\r':
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
)
204 if ((options
& SaveOptions
.OmitDuplicateNamespaces
) == SaveOptions
.OmitDuplicateNamespaces
)
205 s
.NamespaceHandling
|= NamespaceHandling
.OmitDuplicates
;
208 using (XmlWriter w
= XmlWriter
.Create (filename
, s
)) {
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
)
224 if ((options
& SaveOptions
.OmitDuplicateNamespaces
) == SaveOptions
.OmitDuplicateNamespaces
)
225 s
.NamespaceHandling
|= NamespaceHandling
.OmitDuplicates
;
227 using (XmlWriter w
= XmlWriter
.Create (tw
, s
)) {
232 public void Save (XmlWriter w
)
237 public override void WriteTo (XmlWriter w
)
239 if (xmldecl
!= null && xmldecl
.Standalone
!= null)
240 w
.WriteStartDocument (xmldecl
.Standalone
== "yes");
242 w
.WriteStartDocument ();
243 foreach (XNode node
in Nodes ())
247 internal override bool OnAddingObject (object obj
, bool rejectAttribute
, XNode refNode
, bool addFirst
)
249 VerifyAddedNode (obj
, addFirst
);
253 void VerifyAddedNode (object node
, bool addFirst
)
256 throw new InvalidOperationException ("Only a node is allowed here");
259 ValidateWhitespace ((string) node
);
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
) {
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");
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
)
286 if ((options
& SaveOptions
.OmitDuplicateNamespaces
) == SaveOptions
.OmitDuplicateNamespaces
)
287 s
.NamespaceHandling
|= NamespaceHandling
.OmitDuplicates
;
289 using (var writer
= XmlWriter
.Create (stream
, s
)){