The Labs \ Source Viewer \ SSCLI \ System.Xml \ QueryOutputWriter

  1. //------------------------------------------------------------------------------
  2. // <copyright file=QueryOutputWriter.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. namespace System.Xml
  16. {
  17.     using System;
  18.     using System.Globalization;
  19.     using System.IO;
  20.     using System.Collections;
  21.     using System.Xml.Schema;
  22.     using System.Diagnostics;
  23.    
  24.    
  25.     /// <summary>
  26.     /// This writer wraps an XmlRawWriter and inserts additional lexical information into the resulting
  27.     /// Xml 1.0 document:
  28.     /// 1. CData sections
  29.     /// 2. DocType declaration
  30.     ///
  31.     /// It also performs well-formed document checks if standalone="yes" and/or a doc-type-decl is output.
  32.     /// </summary>
  33.     internal class QueryOutputWriter : XmlRawWriter
  34.     {
  35.         private XmlRawWriter wrapped;
  36.         private bool inCDataSection;
  37.         private IList listCDataElems;
  38.         private Hashtable lookupCDataElems;
  39.         private BitStack bitsCData;
  40.         private XmlQualifiedName qnameCData;
  41.         private bool outputDocType, checkWellFormedDoc, hasDocElem, inAttr;
  42.         private string systemId, publicId;
  43.         private int depth;
  44.        
  45.         public QueryOutputWriter(XmlRawWriter writer, XmlWriterSettings settings)
  46.         {
  47.             this.wrapped = writer;
  48.            
  49.             this.systemId = settings.DocTypeSystem;
  50.             this.publicId = settings.DocTypePublic;
  51.            
  52.             if (settings.OutputMethod == XmlOutputMethod.Xml) {
  53.                 // Xml output method shouldn't output doc-type-decl if system ID is not defined (even if public ID is)
  54.                 // Only check for well-formed document if output method is xml
  55.                 if (this.systemId != null) {
  56.                     this.outputDocType = true;
  57.                     this.checkWellFormedDoc = true;
  58.                 }
  59.                
  60.                 // Check for well-formed document if standalone="yes" in an auto-generated xml declaration
  61.                 if (settings.AutoXmlDeclaration && settings.Standalone == XmlStandalone.Yes)
  62.                     this.checkWellFormedDoc = true;
  63.                
  64.                 this.listCDataElems = settings.CDataSectionElements;
  65.                 if (this.listCDataElems != null) {
  66.                     this.bitsCData = new BitStack();
  67.                     this.lookupCDataElems = new Hashtable();
  68.                     this.qnameCData = new XmlQualifiedName();
  69.                    
  70.                     // Add each element name to the lookup table
  71.                     foreach (object name in this.listCDataElems) {
  72.                         if (name is string) {
  73.                             XmlQualifiedName qname = new XmlQualifiedName(name as string, "");
  74.                             this.lookupCDataElems[qname] = qname;
  75.                         }
  76.                         else {
  77.                             Debug.Assert(name is XmlQualifiedName);
  78.                             this.lookupCDataElems[name] = name;
  79.                         }
  80.                     }
  81.                    
  82.                     this.bitsCData.PushBit(false);
  83.                 }
  84.             }
  85.             else if (settings.OutputMethod == XmlOutputMethod.Html) {
  86.                 // Html output method should output doc-type-decl if system ID or public ID is defined
  87.                 if (this.systemId != null || this.publicId != null)
  88.                     this.outputDocType = true;
  89.             }
  90.         }
  91.        
  92.        
  93.         //-----------------------------------------------
  94.         // XmlWriter interface
  95.         //-----------------------------------------------
  96.        
  97.         /// <summary>
  98.         /// Get and set the namespace resolver that's used by this RawWriter to resolve prefixes.
  99.         /// </summary>
  100.         internal override IXmlNamespaceResolver NamespaceResolver {
  101.             get { return this.resolver; }
  102.             set {
  103.                 this.resolver = value;
  104.                 this.wrapped.NamespaceResolver = value;
  105.             }
  106.         }
  107.        
  108.         /// <summary>
  109.         /// Write the xml declaration. This must be the first call.
  110.         /// </summary>
  111.         internal override void WriteXmlDeclaration(XmlStandalone standalone)
  112.         {
  113.             this.wrapped.WriteXmlDeclaration(standalone);
  114.         }
  115.        
  116.         internal override void WriteXmlDeclaration(string xmldecl)
  117.         {
  118.             this.wrapped.WriteXmlDeclaration(xmldecl);
  119.         }
  120.        
  121.         /// <summary>
  122.         /// Return settings provided to factory.
  123.         /// </summary>
  124.         public override XmlWriterSettings Settings {
  125.             get {
  126.                 XmlWriterSettings settings = this.wrapped.Settings;
  127.                
  128.                 settings.ReadOnly = false;
  129.                 settings.DocTypeSystem = this.systemId;
  130.                 settings.DocTypePublic = this.publicId;
  131.                 settings.ReadOnly = true;
  132.                
  133.                 return settings;
  134.             }
  135.         }
  136.        
  137.         /// <summary>
  138.         /// Suppress this explicit call to WriteDocType if information was provided by XmlWriterSettings.
  139.         /// </summary>
  140.         public override void WriteDocType(string name, string pubid, string sysid, string subset)
  141.         {
  142.             if (this.publicId == null && this.systemId == null) {
  143.                 Debug.Assert(!this.outputDocType);
  144.                 this.wrapped.WriteDocType(name, pubid, sysid, subset);
  145.             }
  146.         }
  147.        
  148.         /// <summary>
  149.         /// Check well-formedness, possibly output doc-type-decl, and determine whether this element is a
  150.         /// CData section element.
  151.         /// </summary>
  152.         public override void WriteStartElement(string prefix, string localName, string ns)
  153.         {
  154.             EndCDataSection();
  155.            
  156.             if (this.checkWellFormedDoc) {
  157.                 // Don't allow multiple document elements
  158.                 if (this.depth == 0 && this.hasDocElem)
  159.                     throw new XmlException(Res.Xml_NoMultipleRoots, string.Empty);
  160.                
  161.                 this.depth++;
  162.                 this.hasDocElem = true;
  163.             }
  164.            
  165.             // Output doc-type declaration immediately before first element is output
  166.             if (this.outputDocType) {
  167.                 this.wrapped.WriteDocType(prefix.Length != 0 ? prefix + ":" + localName : localName, this.publicId, this.systemId, null);
  168.                
  169.                 this.outputDocType = false;
  170.             }
  171.            
  172.             this.wrapped.WriteStartElement(prefix, localName, ns);
  173.            
  174.             if (this.lookupCDataElems != null) {
  175.                 // Determine whether this element is a CData section element
  176.                 this.qnameCData.Init(localName, ns);
  177.                 this.bitsCData.PushBit(this.lookupCDataElems[this.qnameCData] != null);
  178.             }
  179.         }
  180.        
  181.         internal override void WriteEndElement(string prefix, string localName, string ns)
  182.         {
  183.             EndCDataSection();
  184.            
  185.             this.wrapped.WriteEndElement(prefix, localName, ns);
  186.            
  187.             if (this.checkWellFormedDoc)
  188.                 this.depth--;
  189.            
  190.             if (this.lookupCDataElems != null)
  191.                 this.bitsCData.PopBit();
  192.         }
  193.        
  194.         internal override void WriteFullEndElement(string prefix, string localName, string ns)
  195.         {
  196.             EndCDataSection();
  197.            
  198.             this.wrapped.WriteFullEndElement(prefix, localName, ns);
  199.            
  200.             if (this.checkWellFormedDoc)
  201.                 this.depth--;
  202.            
  203.             if (this.lookupCDataElems != null)
  204.                 this.bitsCData.PopBit();
  205.         }
  206.        
  207.         internal override void StartElementContent()
  208.         {
  209.             this.wrapped.StartElementContent();
  210.         }
  211.        
  212.         public override void WriteStartAttribute(string prefix, string localName, string ns)
  213.         {
  214.             this.inAttr = true;
  215.             this.wrapped.WriteStartAttribute(prefix, localName, ns);
  216.         }
  217.        
  218.         public override void WriteEndAttribute()
  219.         {
  220.             this.inAttr = false;
  221.             this.wrapped.WriteEndAttribute();
  222.         }
  223.        
  224.         internal override void WriteNamespaceDeclaration(string prefix, string ns)
  225.         {
  226.             this.wrapped.WriteNamespaceDeclaration(prefix, ns);
  227.         }
  228.        
  229.         public override void WriteCData(string text)
  230.         {
  231.             this.wrapped.WriteCData(text);
  232.         }
  233.        
  234.         public override void WriteComment(string text)
  235.         {
  236.             EndCDataSection();
  237.             this.wrapped.WriteComment(text);
  238.         }
  239.        
  240.         public override void WriteProcessingInstruction(string name, string text)
  241.         {
  242.             EndCDataSection();
  243.             this.wrapped.WriteProcessingInstruction(name, text);
  244.         }
  245.        
  246.         public override void WriteWhitespace(string ws)
  247.         {
  248.             if (!this.inAttr && (this.inCDataSection || StartCDataSection()))
  249.                 this.wrapped.WriteCData(ws);
  250.             else
  251.                 this.wrapped.WriteWhitespace(ws);
  252.         }
  253.        
  254.         public override void WriteString(string text)
  255.         {
  256.             if (!this.inAttr && (this.inCDataSection || StartCDataSection()))
  257.                 this.wrapped.WriteCData(text);
  258.             else
  259.                 this.wrapped.WriteString(text);
  260.         }
  261.        
  262.         public override void WriteChars(char[] buffer, int index, int count)
  263.         {
  264.             if (!this.inAttr && (this.inCDataSection || StartCDataSection()))
  265.                 this.wrapped.WriteCData(new string(buffer, index, count));
  266.             else
  267.                 this.wrapped.WriteChars(buffer, index, count);
  268.         }
  269.        
  270.         public override void WriteEntityRef(string name)
  271.         {
  272.             EndCDataSection();
  273.             this.wrapped.WriteEntityRef(name);
  274.         }
  275.        
  276.         public override void WriteCharEntity(char ch)
  277.         {
  278.             EndCDataSection();
  279.             this.wrapped.WriteCharEntity(ch);
  280.         }
  281.        
  282.         public override void WriteSurrogateCharEntity(char lowChar, char highChar)
  283.         {
  284.             EndCDataSection();
  285.             this.wrapped.WriteSurrogateCharEntity(lowChar, highChar);
  286.         }
  287.        
  288.         public override void WriteRaw(char[] buffer, int index, int count)
  289.         {
  290.             if (!this.inAttr && (this.inCDataSection || StartCDataSection()))
  291.                 this.wrapped.WriteCData(new string(buffer, index, count));
  292.             else
  293.                 this.wrapped.WriteRaw(buffer, index, count);
  294.         }
  295.        
  296.         public override void WriteRaw(string data)
  297.         {
  298.             if (!this.inAttr && (this.inCDataSection || StartCDataSection()))
  299.                 this.wrapped.WriteCData(data);
  300.             else
  301.                 this.wrapped.WriteRaw(data);
  302.         }
  303.        
  304.         public override void Close()
  305.         {
  306.             this.wrapped.Close();
  307.            
  308.             if (this.checkWellFormedDoc && !this.hasDocElem) {
  309.                 // Need at least one document element
  310.                 throw new XmlException(Res.Xml_NoRoot, string.Empty);
  311.             }
  312.         }
  313.        
  314.         public override void Flush()
  315.         {
  316.             this.wrapped.Flush();
  317.         }
  318.        
  319.        
  320.         //-----------------------------------------------
  321.         // Helper methods
  322.         //-----------------------------------------------
  323.        
  324.         /// <summary>
  325.         /// Write CData text if element is a CData element. Return true if text should be written
  326.         /// within a CData section.
  327.         /// </summary>
  328.         private bool StartCDataSection()
  329.         {
  330.             Debug.Assert(!this.inCDataSection);
  331.             if (this.lookupCDataElems != null && this.bitsCData.PeekBit()) {
  332.                 this.inCDataSection = true;
  333.                 return true;
  334.             }
  335.             return false;
  336.         }
  337.        
  338.         /// <summary>
  339.         /// No longer write CData text.
  340.         /// </summary>
  341.         private void EndCDataSection()
  342.         {
  343.             this.inCDataSection = false;
  344.         }
  345.     }
  346. }

Developer Fusion