|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
// using System.Security.Permissions;
using System.Runtime.Versioning;
namespace Microsoft.Xml
{
using System;
public enum XmlOutputMethod
{
Xml = 0, // Use Xml 1.0 rules to serialize
Html = 1, // Use Html rules specified by Xslt specification to serialize
Text = 2, // Only serialize text blocks
AutoDetect = 3, // Choose between Xml and Html output methods at runtime (using Xslt rules to do so)
}
/// <summary>
/// Three-state logic enumeration.
/// </summary>
internal enum TriState
{
Unknown = -1,
False = 0,
True = 1,
};
internal enum XmlStandalone
{
// Do not change the constants - XmlBinaryWriter depends in it
Omit = 0,
Yes = 1,
No = 2,
}
// XmlWriterSettings class specifies basic features of an XmlWriter.
public sealed class XmlWriterSettings
{
//
// Fields
//
// Text settings
private Encoding _encoding;
private bool _omitXmlDecl;
private NewLineHandling _newLineHandling;
private string _newLineChars;
private TriState _indent;
private string _indentChars;
private bool _newLineOnAttributes;
private bool _closeOutput;
private NamespaceHandling _namespaceHandling;
// Conformance settings
private ConformanceLevel _conformanceLevel;
private bool _checkCharacters;
private bool _writeEndDocumentOnClose;
// Xslt settings
private XmlOutputMethod _outputMethod;
private List<XmlQualifiedName> _cdataSections = new List<XmlQualifiedName>();
private bool _doNotEscapeUriAttributes;
private bool _mergeCDataSections;
private string _mediaType;
private string _docTypeSystem;
private string _docTypePublic;
private XmlStandalone _standalone;
private bool _autoXmlDecl;
// read-only flag
private bool _isReadOnly;
//
// Constructor
//
public XmlWriterSettings()
{
Initialize();
}
//
// Properties
//
// Text
public Encoding Encoding
{
get
{
return _encoding;
}
set
{
CheckReadOnly("Encoding");
_encoding = value;
}
}
// True if an xml declaration should *not* be written.
public bool OmitXmlDeclaration
{
get
{
return _omitXmlDecl;
}
set
{
CheckReadOnly("OmitXmlDeclaration");
_omitXmlDecl = value;
}
}
// See NewLineHandling enum for details.
public NewLineHandling NewLineHandling
{
get
{
return _newLineHandling;
}
set
{
CheckReadOnly("NewLineHandling");
if ((uint)value > (uint)NewLineHandling.None)
{
throw new ArgumentOutOfRangeException("value");
}
_newLineHandling = value;
}
}
// Line terminator string. By default, this is a carriage return followed by a line feed ("\r\n").
public string NewLineChars
{
get
{
return _newLineChars;
}
set
{
CheckReadOnly("NewLineChars");
if (value == null)
{
throw new ArgumentNullException("value");
}
_newLineChars = value;
}
}
// True if output should be indented using rules that are appropriate to the output rules (i.e. Xml, Html, etc).
public bool Indent
{
get
{
return _indent == TriState.True;
}
set
{
CheckReadOnly("Indent");
_indent = value ? TriState.True : TriState.False;
}
}
// Characters to use when indenting. This is usually tab or some spaces, but can be anything.
public string IndentChars
{
get
{
return _indentChars;
}
set
{
CheckReadOnly("IndentChars");
if (value == null)
{
throw new ArgumentNullException("value");
}
_indentChars = value;
}
}
// Whether or not indent attributes on new lines.
public bool NewLineOnAttributes
{
get
{
return _newLineOnAttributes;
}
set
{
CheckReadOnly("NewLineOnAttributes");
_newLineOnAttributes = value;
}
}
// Whether or not the XmlWriter should close the underlying stream or TextWriter when Close is called on the XmlWriter.
public bool CloseOutput
{
get
{
return _closeOutput;
}
set
{
CheckReadOnly("CloseOutput");
_closeOutput = value;
}
}
// Conformance
// See ConformanceLevel enum for details.
public ConformanceLevel ConformanceLevel
{
get
{
return _conformanceLevel;
}
set
{
CheckReadOnly("ConformanceLevel");
if ((uint)value > (uint)ConformanceLevel.Document)
{
throw new ArgumentOutOfRangeException("value");
}
_conformanceLevel = value;
}
}
// Whether or not to check content characters that they are valid XML characters.
public bool CheckCharacters
{
get
{
return _checkCharacters;
}
set
{
CheckReadOnly("CheckCharacters");
_checkCharacters = value;
}
}
// Whether or not to remove duplicate namespace declarations
public NamespaceHandling NamespaceHandling
{
get
{
return _namespaceHandling;
}
set
{
CheckReadOnly("NamespaceHandling");
if ((uint)value > (uint)(NamespaceHandling.OmitDuplicates))
{
throw new ArgumentOutOfRangeException("value");
}
_namespaceHandling = value;
}
}
//Whether or not to auto complete end-element when close/dispose
public bool WriteEndDocumentOnClose
{
get
{
return _writeEndDocumentOnClose;
}
set
{
CheckReadOnly("WriteEndDocumentOnClose");
_writeEndDocumentOnClose = value;
}
}
// Specifies the method (Html, Xml, etc.) that will be used to serialize the result tree.
public XmlOutputMethod OutputMethod
{
get
{
return _outputMethod;
}
internal set
{
_outputMethod = value;
}
}
//
// Public methods
//
public void Reset()
{
CheckReadOnly("Reset");
Initialize();
}
// Deep clone all settings (except read-only, which is always set to false). The original and new objects
// can now be set independently of each other.
public XmlWriterSettings Clone()
{
XmlWriterSettings clonedSettings = MemberwiseClone() as XmlWriterSettings;
// Deep clone shared settings that are not immutable
clonedSettings._cdataSections = new List<XmlQualifiedName>(_cdataSections);
clonedSettings._isReadOnly = false;
return clonedSettings;
}
//
// Internal properties
//
// Set of XmlQualifiedNames that identify any elements that need to have text children wrapped in CData sections.
internal List<XmlQualifiedName> CDataSectionElements
{
get
{
Debug.Assert(_cdataSections != null);
return _cdataSections;
}
}
// Used in Html writer to disable encoding of uri attributes
public bool DoNotEscapeUriAttributes
{
get
{
return _doNotEscapeUriAttributes;
}
set
{
CheckReadOnly("DoNotEscapeUriAttributes");
_doNotEscapeUriAttributes = value;
}
}
internal bool MergeCDataSections
{
get
{
return _mergeCDataSections;
}
set
{
CheckReadOnly("MergeCDataSections");
_mergeCDataSections = value;
}
}
// Used in Html writer when writing Meta element. Null denotes the default media type.
internal string MediaType
{
get
{
return _mediaType;
}
set
{
CheckReadOnly("MediaType");
_mediaType = value;
}
}
// System Id in doc-type declaration. Null denotes the absence of the system Id.
internal string DocTypeSystem
{
get
{
return _docTypeSystem;
}
set
{
CheckReadOnly("DocTypeSystem");
_docTypeSystem = value;
}
}
// Public Id in doc-type declaration. Null denotes the absence of the public Id.
internal string DocTypePublic
{
get
{
return _docTypePublic;
}
set
{
CheckReadOnly("DocTypePublic");
_docTypePublic = value;
}
}
// Yes for standalone="yes", No for standalone="no", and Omit for no standalone.
internal XmlStandalone Standalone
{
get
{
return _standalone;
}
set
{
CheckReadOnly("Standalone");
_standalone = value;
}
}
// True if an xml declaration should automatically be output (no need to call WriteStartDocument)
internal bool AutoXmlDeclaration
{
get
{
return _autoXmlDecl;
}
set
{
CheckReadOnly("AutoXmlDeclaration");
_autoXmlDecl = value;
}
}
// If TriState.Unknown, then Indent property was not explicitly set. In this case, the AutoDetect output
// method will default to Indent=true for Html and Indent=false for Xml.
internal TriState IndentInternal
{
get
{
return _indent;
}
set
{
_indent = value;
}
}
internal bool IsQuerySpecific
{
get
{
return _cdataSections.Count != 0 || _docTypePublic != null ||
_docTypeSystem != null || _standalone == XmlStandalone.Yes;
}
}
// [ResourceConsumption(ResourceScope.Machine)]
// [ResourceExposure(ResourceScope.Machine)]
internal XmlWriter CreateWriter(string outputFileName)
{
if (outputFileName == null)
{
throw new ArgumentNullException("outputFileName");
}
// need to clone the settigns so that we can set CloseOutput to true to make sure the stream gets closed in the end
XmlWriterSettings newSettings = this;
if (!newSettings.CloseOutput)
{
newSettings = newSettings.Clone();
newSettings.CloseOutput = true;
}
FileStream fs = null;
try
{
// open file stream
fs = new FileStream(outputFileName, FileMode.Create, FileAccess.Write, FileShare.Read);
// create writer
return newSettings.CreateWriter(fs);
}
catch
{
if (fs != null)
{
fs.Close();
}
throw;
}
}
internal XmlWriter CreateWriter(Stream output)
{
if (output == null)
{
throw new ArgumentNullException("output");
}
XmlWriter writer;
// create raw writer
Debug.Assert(Encoding.UTF8.WebName == "utf-8");
if (this.Encoding.WebName == "utf-8")
{ // Encoding.CodePage is not supported in Silverlight
// create raw UTF-8 writer
switch (this.OutputMethod)
{
case XmlOutputMethod.Xml:
if (this.Indent)
{
writer = new XmlUtf8RawTextWriterIndent(output, this);
}
else
{
writer = new XmlUtf8RawTextWriter(output, this);
}
break;
case XmlOutputMethod.Html:
if (this.Indent)
{
writer = new HtmlUtf8RawTextWriterIndent(output, this);
}
else
{
writer = new HtmlUtf8RawTextWriter(output, this);
}
break;
case XmlOutputMethod.Text:
writer = new TextUtf8RawTextWriter(output, this);
break;
case XmlOutputMethod.AutoDetect:
writer = new XmlAutoDetectWriter(output, this);
break;
default:
Debug.Assert(false, "Invalid XmlOutputMethod setting.");
return null;
}
}
else
{
// Otherwise, create a general-purpose writer than can do any encoding
switch (this.OutputMethod)
{
case XmlOutputMethod.Xml:
if (this.Indent)
{
writer = new XmlEncodedRawTextWriterIndent(output, this);
}
else
{
writer = new XmlEncodedRawTextWriter(output, this);
}
break;
case XmlOutputMethod.Html:
if (this.Indent)
{
writer = new HtmlEncodedRawTextWriterIndent(output, this);
}
else
{
writer = new HtmlEncodedRawTextWriter(output, this);
}
break;
case XmlOutputMethod.Text:
writer = new TextEncodedRawTextWriter(output, this);
break;
case XmlOutputMethod.AutoDetect:
writer = new XmlAutoDetectWriter(output, this);
break;
default:
Debug.Assert(false, "Invalid XmlOutputMethod setting.");
return null;
}
}
// Wrap with Xslt/XQuery specific writer if needed;
// XmlOutputMethod.AutoDetect writer does this lazily when it creates the underlying Xml or Html writer.
if (this.OutputMethod != XmlOutputMethod.AutoDetect)
{
if (this.IsQuerySpecific)
{
// Create QueryOutputWriter if CData sections or DocType need to be tracked
writer = new QueryOutputWriter((XmlRawWriter)writer, this);
}
}
// wrap with well-formed writer
writer = new XmlWellFormedWriter(writer, this);
return writer;
}
internal XmlWriter CreateWriter(TextWriter output)
{
if (output == null)
{
throw new ArgumentNullException("output");
}
XmlWriter writer;
// create raw writer
switch (this.OutputMethod)
{
case XmlOutputMethod.Xml:
if (this.Indent)
{
writer = new XmlEncodedRawTextWriterIndent(output, this);
}
else
{
writer = new XmlEncodedRawTextWriter(output, this);
}
break;
case XmlOutputMethod.Html:
if (this.Indent)
{
writer = new HtmlEncodedRawTextWriterIndent(output, this);
}
else
{
writer = new HtmlEncodedRawTextWriter(output, this);
}
break;
case XmlOutputMethod.Text:
writer = new TextEncodedRawTextWriter(output, this);
break;
case XmlOutputMethod.AutoDetect:
writer = new XmlAutoDetectWriter(output, this);
break;
default:
Debug.Assert(false, "Invalid XmlOutputMethod setting.");
return null;
}
// XmlOutputMethod.AutoDetect writer does this lazily when it creates the underlying Xml or Html writer.
if (this.OutputMethod != XmlOutputMethod.AutoDetect)
{
if (this.IsQuerySpecific)
{
// Create QueryOutputWriter if CData sections or DocType need to be tracked
writer = new QueryOutputWriter((XmlRawWriter)writer, this);
}
}
// wrap with well-formed writer
writer = new XmlWellFormedWriter(writer, this);
return writer;
}
internal XmlWriter CreateWriter(XmlWriter output)
{
if (output == null)
{
throw new ArgumentNullException("output");
}
return AddConformanceWrapper(output);
}
internal bool ReadOnly
{
get
{
return _isReadOnly;
}
set
{
_isReadOnly = value;
}
}
private void CheckReadOnly(string propertyName)
{
if (_isReadOnly)
{
throw new XmlException(ResXml.Xml_ReadOnlyProperty, this.GetType().Name + '.' + propertyName);
}
}
//
// Private methods
//
private void Initialize()
{
_encoding = Encoding.UTF8;
_omitXmlDecl = false;
_newLineHandling = NewLineHandling.Replace;
_newLineChars = Environment.NewLine; // "\r\n" on Windows, "\n" on Unix
_indent = TriState.Unknown;
_indentChars = " ";
_newLineOnAttributes = false;
_closeOutput = false;
_namespaceHandling = NamespaceHandling.Default;
_conformanceLevel = ConformanceLevel.Document;
_checkCharacters = true;
_writeEndDocumentOnClose = true;
_outputMethod = XmlOutputMethod.Xml;
_cdataSections.Clear();
_mergeCDataSections = false;
_mediaType = null;
_docTypeSystem = null;
_docTypePublic = null;
_standalone = XmlStandalone.Omit;
_doNotEscapeUriAttributes = false;
_isReadOnly = false;
}
private XmlWriter AddConformanceWrapper(XmlWriter baseWriter)
{
ConformanceLevel confLevel = ConformanceLevel.Auto;
XmlWriterSettings baseWriterSettings = baseWriter.Settings;
bool checkValues = false;
bool checkNames = false;
bool replaceNewLines = false;
bool needWrap = false;
if (baseWriterSettings == null)
{
// assume the V1 writer already do all conformance checking;
// wrap only if NewLineHandling == Replace or CheckCharacters is true
if (_newLineHandling == NewLineHandling.Replace)
{
replaceNewLines = true;
needWrap = true;
}
if (_checkCharacters)
{
checkValues = true;
needWrap = true;
}
}
else
{
if (_conformanceLevel != baseWriterSettings.ConformanceLevel)
{
confLevel = this.ConformanceLevel;
needWrap = true;
}
if (_checkCharacters && !baseWriterSettings.CheckCharacters)
{
checkValues = true;
checkNames = confLevel == ConformanceLevel.Auto;
needWrap = true;
}
if (_newLineHandling == NewLineHandling.Replace &&
baseWriterSettings.NewLineHandling == NewLineHandling.None)
{
replaceNewLines = true;
needWrap = true;
}
}
XmlWriter writer = baseWriter;
if (needWrap)
{
if (confLevel != ConformanceLevel.Auto)
{
writer = new XmlWellFormedWriter(writer, this);
}
if (checkValues || replaceNewLines)
{
writer = new XmlCharCheckingWriter(writer, checkValues, checkNames, replaceNewLines, this.NewLineChars);
}
}
if (this.IsQuerySpecific && (baseWriterSettings == null || !baseWriterSettings.IsQuerySpecific))
{
// Create QueryOutputWriterV1 if CData sections or DocType need to be tracked
writer = new QueryOutputWriterV1(writer, this);
}
return writer;
}
//
// Internal methods
//
internal void GetObjectData(object writer) { }
internal XmlWriterSettings(object reader) { }
}
}
|