| File: FrameworkFork\Microsoft.Xml\Xml\Core\QueryOutputWriter.cs | Web Access |
| Project: src\src\dotnet-svcutil\lib\src\dotnet-svcutil-lib.csproj (dotnet-svcutil-lib) |
// 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. namespace Microsoft.Xml { using System; using System.Globalization; using System.IO; using System.Collections.Generic; using Microsoft.Xml.Schema; using System.Diagnostics; /// <summary> /// This writer wraps an XmlRawWriter and inserts additional lexical information into the resulting /// Xml 1.0 document: /// 1. CData sections /// 2. DocType declaration /// /// It also performs well-formed document checks if standalone="yes" and/or a doc-type-decl is output. /// </summary> internal class QueryOutputWriter : XmlRawWriter { private XmlRawWriter _wrapped; private bool _inCDataSection; private Dictionary<XmlQualifiedName, int> _lookupCDataElems; private BitStack _bitsCData; private XmlQualifiedName _qnameCData; private bool _outputDocType,_checkWellFormedDoc,_hasDocElem,_inAttr; private string _systemId,_publicId; private int _depth; public QueryOutputWriter(XmlRawWriter writer, XmlWriterSettings settings) { _wrapped = writer; _systemId = settings.DocTypeSystem; _publicId = settings.DocTypePublic; if (settings.OutputMethod == XmlOutputMethod.Xml) { // Xml output method shouldn't output doc-type-decl if system ID is not defined (even if public ID is) // Only check for well-formed document if output method is xml if (_systemId != null) { _outputDocType = true; _checkWellFormedDoc = true; } // Check for well-formed document if standalone="yes" in an auto-generated xml declaration if (settings.AutoXmlDeclaration && settings.Standalone == XmlStandalone.Yes) _checkWellFormedDoc = true; if (settings.CDataSectionElements.Count > 0) { _bitsCData = new BitStack(); _lookupCDataElems = new Dictionary<XmlQualifiedName, int>(); _qnameCData = new XmlQualifiedName(); // Add each element name to the lookup table foreach (XmlQualifiedName name in settings.CDataSectionElements) { _lookupCDataElems[name] = 0; } _bitsCData.PushBit(false); } } else if (settings.OutputMethod == XmlOutputMethod.Html) { // Html output method should output doc-type-decl if system ID or public ID is defined if (_systemId != null || _publicId != null) _outputDocType = true; } } //----------------------------------------------- // XmlWriter interface //----------------------------------------------- /// <summary> /// Get and set the namespace resolver that's used by this RawWriter to resolve prefixes. /// </summary> internal override IXmlNamespaceResolver NamespaceResolver { get { return this.resolver; } set { this.resolver = value; _wrapped.NamespaceResolver = value; } } /// <summary> /// Write the xml declaration. This must be the first call. /// </summary> internal override void WriteXmlDeclaration(XmlStandalone standalone) { _wrapped.WriteXmlDeclaration(standalone); } internal override void WriteXmlDeclaration(string xmldecl) { _wrapped.WriteXmlDeclaration(xmldecl); } /// <summary> /// Return settings provided to factory. /// </summary> public override XmlWriterSettings Settings { get { XmlWriterSettings settings = _wrapped.Settings; settings.ReadOnly = false; settings.DocTypeSystem = _systemId; settings.DocTypePublic = _publicId; settings.ReadOnly = true; return settings; } } /// <summary> /// Suppress this explicit call to WriteDocType if information was provided by XmlWriterSettings. /// </summary> public override void WriteDocType(string name, string pubid, string sysid, string subset) { if (_publicId == null && _systemId == null) { Debug.Assert(!_outputDocType); _wrapped.WriteDocType(name, pubid, sysid, subset); } } /// <summary> /// Check well-formedness, possibly output doc-type-decl, and determine whether this element is a /// CData section element. /// </summary> public override void WriteStartElement(string prefix, string localName, string ns) { EndCDataSection(); if (_checkWellFormedDoc) { // Don't allow multiple document elements if (_depth == 0 && _hasDocElem) throw new XmlException(ResXml.Xml_NoMultipleRoots, string.Empty); _depth++; _hasDocElem = true; } // Output doc-type declaration immediately before first element is output if (_outputDocType) { _wrapped.WriteDocType( prefix.Length != 0 ? prefix + ":" + localName : localName, _publicId, _systemId, null); _outputDocType = false; } _wrapped.WriteStartElement(prefix, localName, ns); if (_lookupCDataElems != null) { // Determine whether this element is a CData section element _qnameCData.Init(localName, ns); _bitsCData.PushBit(_lookupCDataElems.ContainsKey(_qnameCData)); } } internal override void WriteEndElement(string prefix, string localName, string ns) { EndCDataSection(); _wrapped.WriteEndElement(prefix, localName, ns); if (_checkWellFormedDoc) _depth--; if (_lookupCDataElems != null) _bitsCData.PopBit(); } internal override void WriteFullEndElement(string prefix, string localName, string ns) { EndCDataSection(); _wrapped.WriteFullEndElement(prefix, localName, ns); if (_checkWellFormedDoc) _depth--; if (_lookupCDataElems != null) _bitsCData.PopBit(); } internal override void StartElementContent() { _wrapped.StartElementContent(); } public override void WriteStartAttribute(string prefix, string localName, string ns) { _inAttr = true; _wrapped.WriteStartAttribute(prefix, localName, ns); } public override void WriteEndAttribute() { _inAttr = false; _wrapped.WriteEndAttribute(); } internal override void WriteNamespaceDeclaration(string prefix, string ns) { _wrapped.WriteNamespaceDeclaration(prefix, ns); } internal override bool SupportsNamespaceDeclarationInChunks { get { return _wrapped.SupportsNamespaceDeclarationInChunks; } } internal override void WriteStartNamespaceDeclaration(string prefix) { _wrapped.WriteStartNamespaceDeclaration(prefix); } internal override void WriteEndNamespaceDeclaration() { _wrapped.WriteEndNamespaceDeclaration(); } public override void WriteCData(string text) { _wrapped.WriteCData(text); } public override void WriteComment(string text) { EndCDataSection(); _wrapped.WriteComment(text); } public override void WriteProcessingInstruction(string name, string text) { EndCDataSection(); _wrapped.WriteProcessingInstruction(name, text); } public override void WriteWhitespace(string ws) { if (!_inAttr && (_inCDataSection || StartCDataSection())) _wrapped.WriteCData(ws); else _wrapped.WriteWhitespace(ws); } public override void WriteString(string text) { if (!_inAttr && (_inCDataSection || StartCDataSection())) _wrapped.WriteCData(text); else _wrapped.WriteString(text); } public override void WriteChars(char[] buffer, int index, int count) { if (!_inAttr && (_inCDataSection || StartCDataSection())) _wrapped.WriteCData(new string(buffer, index, count)); else _wrapped.WriteChars(buffer, index, count); } public override void WriteEntityRef(string name) { EndCDataSection(); _wrapped.WriteEntityRef(name); } public override void WriteCharEntity(char ch) { EndCDataSection(); _wrapped.WriteCharEntity(ch); } public override void WriteSurrogateCharEntity(char lowChar, char highChar) { EndCDataSection(); _wrapped.WriteSurrogateCharEntity(lowChar, highChar); } public override void WriteRaw(char[] buffer, int index, int count) { if (!_inAttr && (_inCDataSection || StartCDataSection())) _wrapped.WriteCData(new string(buffer, index, count)); else _wrapped.WriteRaw(buffer, index, count); } public override void WriteRaw(string data) { if (!_inAttr && (_inCDataSection || StartCDataSection())) _wrapped.WriteCData(data); else _wrapped.WriteRaw(data); } public override void Close() { _wrapped.Close(); if (_checkWellFormedDoc && !_hasDocElem) { // Need at least one document element throw new XmlException(ResXml.Xml_NoRoot, string.Empty); } } public override void Flush() { _wrapped.Flush(); } //----------------------------------------------- // Helper methods //----------------------------------------------- /// <summary> /// Write CData text if element is a CData element. Return true if text should be written /// within a CData section. /// </summary> private bool StartCDataSection() { Debug.Assert(!_inCDataSection); if (_lookupCDataElems != null && _bitsCData.PeekBit()) { _inCDataSection = true; return true; } return false; } /// <summary> /// No longer write CData text. /// </summary> private void EndCDataSection() { _inCDataSection = false; } } }