// // Authors: // Atsushi Enomoto // // Copyright 2007 Novell (http://www.novell.com) // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Text; using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; namespace System.Xml.Linq { public class XDocument : XContainer { XDeclaration xmldecl; public XDocument () { } public XDocument (params object [] content) { Add (content); } public XDocument (XDeclaration xmldecl, params object [] content) { Declaration = xmldecl; Add (content); } public XDocument (XDocument other) { foreach (object o in other.Nodes ()) Add (XUtil.Clone (o)); } public XDeclaration Declaration { get { return xmldecl; } set { xmldecl = value; } } public XDocumentType DocumentType { get { foreach (object o in Nodes ()) if (o is XDocumentType) return (XDocumentType) o; return null; } } public override XmlNodeType NodeType { get { return XmlNodeType.Document; } } public XElement Root { get { foreach (object o in Nodes ()) if (o is XElement) return (XElement) o; return null; } } public static XDocument Load (string uri) { return Load (uri, LoadOptions.None); } public static XDocument Load (string uri, LoadOptions options) { XmlReaderSettings s = new XmlReaderSettings (); s.IgnoreWhitespace = (options & LoadOptions.PreserveWhitespace) == 0; using (XmlReader r = XmlReader.Create (uri, s)) { return LoadCore (r, options); } } public static XDocument Load (TextReader reader) { return Load (reader, LoadOptions.None); } public static XDocument Load (TextReader reader, LoadOptions options) { XmlReaderSettings s = new XmlReaderSettings (); s.IgnoreWhitespace = (options & LoadOptions.PreserveWhitespace) == 0; using (XmlReader r = XmlReader.Create (reader, s)) { return LoadCore (r, options); } } public static XDocument Load (XmlReader reader) { return Load (reader, LoadOptions.None); } public static XDocument Load (XmlReader reader, LoadOptions options) { XmlReaderSettings s = reader.Settings.Clone (); s.IgnoreWhitespace = (options & LoadOptions.PreserveWhitespace) == 0; using (XmlReader r = XmlReader.Create (reader, s)) { return LoadCore (r, options); } } static XDocument LoadCore (XmlReader reader, LoadOptions options) { XDocument doc = new XDocument (); doc.ReadContent (reader, options); return doc; } void ReadContent (XmlReader reader, LoadOptions options) { if (reader.ReadState == ReadState.Initial) reader.Read (); if (reader.NodeType == XmlNodeType.XmlDeclaration) { Declaration = new XDeclaration ( reader.GetAttribute ("version"), reader.GetAttribute ("encoding"), reader.GetAttribute ("standalone")); reader.Read (); } ReadContentFrom (reader, options); if (Root == null) throw new InvalidOperationException ("The document element is missing."); } static void ValidateWhitespace (string s) { for (int i = 0; i < s.Length; i++) switch (s [i]) { case ' ': case '\t': case '\n': case '\r': continue; default: throw new ArgumentException ("Non-whitespace text appears directly in the document."); } } public static XDocument Parse (string s) { return Parse (s, LoadOptions.None); } public static XDocument Parse (string s, LoadOptions options) { return Load (new StringReader (s), options); } public void Save (string filename) { Save (filename, SaveOptions.None); } public void Save (string filename, SaveOptions options) { XmlWriterSettings s = new XmlWriterSettings (); if ((options & SaveOptions.DisableFormatting) == 0) { // hacky! s.Indent = true; s.IndentChars = String.Empty; s.NewLineChars = String.Empty; } using (XmlWriter w = XmlWriter.Create (filename)) { Save (w); } } public void Save (TextWriter tw) { Save (tw, SaveOptions.None); } public void Save (TextWriter tw, SaveOptions options) { XmlWriterSettings s = new XmlWriterSettings (); if ((options & SaveOptions.DisableFormatting) == 0) { // hacky! s.Indent = true; s.IndentChars = String.Empty; s.NewLineChars = String.Empty; } using (XmlWriter w = XmlWriter.Create (tw)) { Save (w); } } public void Save (XmlWriter w) { WriteTo (w); } public override void WriteTo (XmlWriter w) { if (xmldecl != null) { if (xmldecl.Standalone != null) w.WriteStartDocument (xmldecl.Standalone == "yes"); else w.WriteStartDocument (); } foreach (XNode node in Nodes ()) node.WriteTo (w); } internal override void OnAdded (XNode node, bool addFirst) { if (node == null) throw new InvalidOperationException ("Only a node is allowed here"); if (node is XText) ValidateWhitespace (((XText) node).Value); else if (node is XDocumentType) { if (DocumentType != null) throw new InvalidOperationException ("There already is another document type declaration"); if (Root != null && !addFirst) throw new InvalidOperationException ("A document type cannot be added after the document element"); } else if (node is XElement) { if (Root != null) throw new InvalidOperationException ("There already is another document element"); if (DocumentType != null && addFirst) throw new InvalidOperationException ("An element cannot be added before the document type declaration"); } } } }