// // 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 declaration, params object [] content) { Declaration = declaration; 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 (); #if !MOONLIGHT s.ProhibitDtd = false; // see XNodeNavigatorTest.MoveToId(). #endif s.IgnoreWhitespace = (options & LoadOptions.PreserveWhitespace) == 0; using (XmlReader r = XmlReader.Create (uri, s)) { return LoadCore (r, options); } } public static XDocument Load (Stream stream) { return Load (new StreamReader (stream), LoadOptions.None); } public static XDocument Load (Stream stream, LoadOptions options) { return Load (new StreamReader (stream), options); } public static XDocument Load (TextReader textReader) { return Load (textReader, LoadOptions.None); } public static XDocument Load (TextReader textReader, LoadOptions options) { XmlReaderSettings s = new XmlReaderSettings (); #if !MOONLIGHT s.ProhibitDtd = false; // see XNodeNavigatorTest.MoveToId(). #endif s.IgnoreWhitespace = (options & LoadOptions.PreserveWhitespace) == 0; using (XmlReader r = XmlReader.Create (textReader, 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 != null ? reader.Settings.Clone () : new XmlReaderSettings (); 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 (); this.FillLineInfoAndBaseUri (reader, options); 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 text) { return Parse (text, LoadOptions.None); } public static XDocument Parse (string text, LoadOptions options) { return Load (new StringReader (text), 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) == SaveOptions.None) s.Indent = true; #if NET_4_0 if ((options & SaveOptions.OmitDuplicateNamespaces) == SaveOptions.OmitDuplicateNamespaces) s.NamespaceHandling |= NamespaceHandling.OmitDuplicates; #endif using (XmlWriter w = XmlWriter.Create (fileName, s)) { Save (w); } } public void Save (TextWriter textWriter) { Save (textWriter, SaveOptions.None); } public void Save (TextWriter textWriter, SaveOptions options) { XmlWriterSettings s = new XmlWriterSettings (); if ((options & SaveOptions.DisableFormatting) == SaveOptions.None) s.Indent = true; #if NET_4_0 if ((options & SaveOptions.OmitDuplicateNamespaces) == SaveOptions.OmitDuplicateNamespaces) s.NamespaceHandling |= NamespaceHandling.OmitDuplicates; #endif using (XmlWriter w = XmlWriter.Create (textWriter, s)) { Save (w); } } public void Save (XmlWriter writer) { WriteTo (writer); } public override void WriteTo (XmlWriter writer) { if (xmldecl != null && xmldecl.Standalone != null) writer.WriteStartDocument (xmldecl.Standalone == "yes"); else writer.WriteStartDocument (); foreach (XNode node in Nodes ()) node.WriteTo (writer); } internal override bool OnAddingObject (object obj, bool rejectAttribute, XNode refNode, bool addFirst) { VerifyAddedNode (obj, addFirst); return false; } void VerifyAddedNode (object node, bool addFirst) { if (node == null) throw new InvalidOperationException ("Only a node is allowed here"); if (node is string) ValidateWhitespace ((string) node); 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"); } } #if NET_4_0 public void Save (Stream stream) { Save (stream, SaveOptions.None); } public void Save (Stream stream, SaveOptions options) { XmlWriterSettings s = new XmlWriterSettings (); if ((options & SaveOptions.DisableFormatting) == SaveOptions.None) s.Indent = true; if ((options & SaveOptions.OmitDuplicateNamespaces) == SaveOptions.OmitDuplicateNamespaces) s.NamespaceHandling |= NamespaceHandling.OmitDuplicates; using (var writer = XmlWriter.Create (stream, s)){ Save (writer); } } #endif } }