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

  1. //------------------------------------------------------------------------------
  2. // <copyright file="XmlEventCache.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.Diagnostics;
  19.     using System.Text;
  20.     using System.IO;
  21.     using System.Collections;
  22.     using System.Xml.Schema;
  23.    
  24.    
  25.     /// <summary>
  26.     /// Caches sequence of XmlEvents so that they can be replayed later.
  27.     /// </summary>
  28.     internal sealed class XmlEventCache : XmlRawWriter
  29.     {
  30.         private ArrayList pages;
  31.         // All event pages
  32.         private XmlEvent[] pageCurr;
  33.         // Page that is currently being built
  34.         private int pageSize;
  35.         // Number of events in pageCurr
  36.         private bool hasRootNode;
  37.         // True if the cached document has a root node, false if it's a fragment
  38.         private string singleText;
  39.         // If document consists of a single text node, cache it here rather than creating pages
  40.         private string baseUri;
  41.         // Base Uri of document
  42.         private enum XmlEventType
  43.         {
  44.             Unknown = 0,
  45.             DocType,
  46.             StartElem,
  47.             StartAttr,
  48.             EndAttr,
  49.             CData,
  50.             Comment,
  51.             PI,
  52.             Whitespace,
  53.             String,
  54.             Raw,
  55.             EntRef,
  56.             CharEnt,
  57.             SurrCharEnt,
  58.             Base64,
  59.             BinHex,
  60.             XmlDecl1,
  61.             XmlDecl2,
  62.             StartContent,
  63.             EndElem,
  64.             FullEndElem,
  65.             Nmsp,
  66.             EndBase64,
  67.             Close,
  68.             Flush,
  69.             Dispose
  70.         }
  71.        
  72.         #if DEBUG
  73.         private const int InitialPageSize = 4;
  74.         #else
  75.         private const int InitialPageSize = 32;
  76.         #endif
  77.        
  78.         public XmlEventCache(string baseUri, bool hasRootNode)
  79.         {
  80.             this.baseUri = baseUri;
  81.             this.hasRootNode = hasRootNode;
  82.         }
  83.        
  84.         public void EndEvents()
  85.         {
  86.             if (this.singleText == null)
  87.                 AddEvent(XmlEventType.Unknown);
  88.         }
  89.        
  90.        
  91.         //-----------------------------------------------
  92.         // XmlEventCache methods
  93.         //-----------------------------------------------
  94.        
  95.         /// <summary>
  96.         /// Return Base Uri of the document.
  97.         /// </summary>
  98.         public string BaseUri {
  99.             get { return this.baseUri; }
  100.         }
  101.        
  102.         /// <summary>
  103.         /// Return true if the cached document has a root node, false if it's a fragment.
  104.         /// </summary>
  105.         public bool HasRootNode {
  106.             get { return this.hasRootNode; }
  107.         }
  108.        
  109.         /// <summary>
  110.         /// Replay all cached events to an XmlWriter.
  111.         /// </summary>
  112.         public void EventsToWriter(XmlWriter writer)
  113.         {
  114.             XmlEvent[] page;
  115.             int idxPage;
  116.             int idxEvent;
  117.             byte[] bytes;
  118.             char[] chars;
  119.             XmlRawWriter rawWriter;
  120.            
  121.             // Special-case single text node at the top-level
  122.             if (this.singleText != null) {
  123.                 writer.WriteString(this.singleText);
  124.                 return;
  125.             }
  126.            
  127.             rawWriter = writer as XmlRawWriter;
  128.            
  129.             // Loop over set of pages
  130.             for (idxPage = 0; idxPage < this.pages.Count; idxPage++) {
  131.                 page = this.pages[idxPage] as XmlEvent[];
  132.                
  133.                 // Loop over events in each page
  134.                 for (idxEvent = 0; idxEvent < page.Length; idxEvent++) {
  135.                     switch (page[idxEvent].EventType) {
  136.                         case XmlEventType.Unknown:
  137.                             // No more events
  138.                             Debug.Assert(idxPage + 1 == this.pages.Count);
  139.                             return;
  140.                         case XmlEventType.DocType:
  141.                            
  142.                             writer.WriteDocType(page[idxEvent].String1, page[idxEvent].String2, page[idxEvent].String3, (string)page[idxEvent].Object);
  143.                             break;
  144.                         case XmlEventType.StartElem:
  145.                            
  146.                             writer.WriteStartElement(page[idxEvent].String1, page[idxEvent].String2, page[idxEvent].String3);
  147.                             break;
  148.                         case XmlEventType.StartAttr:
  149.                            
  150.                             writer.WriteStartAttribute(page[idxEvent].String1, page[idxEvent].String2, page[idxEvent].String3);
  151.                             break;
  152.                         case XmlEventType.EndAttr:
  153.                            
  154.                             writer.WriteEndAttribute();
  155.                             break;
  156.                         case XmlEventType.CData:
  157.                            
  158.                             writer.WriteCData(page[idxEvent].String1);
  159.                             break;
  160.                         case XmlEventType.Comment:
  161.                            
  162.                             writer.WriteComment(page[idxEvent].String1);
  163.                             break;
  164.                         case XmlEventType.PI:
  165.                            
  166.                             writer.WriteProcessingInstruction(page[idxEvent].String1, page[idxEvent].String2);
  167.                             break;
  168.                         case XmlEventType.Whitespace:
  169.                            
  170.                             writer.WriteWhitespace(page[idxEvent].String1);
  171.                             break;
  172.                         case XmlEventType.String:
  173.                            
  174.                             writer.WriteString(page[idxEvent].String1);
  175.                             break;
  176.                         case XmlEventType.Raw:
  177.                            
  178.                             writer.WriteRaw(page[idxEvent].String1);
  179.                             break;
  180.                         case XmlEventType.EntRef:
  181.                            
  182.                             writer.WriteEntityRef(page[idxEvent].String1);
  183.                             break;
  184.                         case XmlEventType.CharEnt:
  185.                            
  186.                             writer.WriteCharEntity((char)page[idxEvent].Object);
  187.                             break;
  188.                         case XmlEventType.SurrCharEnt:
  189.                            
  190.                             chars = (char[])page[idxEvent].Object;
  191.                             writer.WriteSurrogateCharEntity(chars[0], chars[1]);
  192.                             break;
  193.                         case XmlEventType.Base64:
  194.                            
  195.                             bytes = (byte[])page[idxEvent].Object;
  196.                             writer.WriteBase64(bytes, 0, bytes.Length);
  197.                             break;
  198.                         case XmlEventType.BinHex:
  199.                            
  200.                             bytes = (byte[])page[idxEvent].Object;
  201.                             writer.WriteBinHex(bytes, 0, bytes.Length);
  202.                             break;
  203.                         case XmlEventType.XmlDecl1:
  204.                            
  205.                             if (rawWriter != null)
  206.                                 rawWriter.WriteXmlDeclaration((XmlStandalone)page[idxEvent].Object);
  207.                             break;
  208.                         case XmlEventType.XmlDecl2:
  209.                            
  210.                             if (rawWriter != null)
  211.                                 rawWriter.WriteXmlDeclaration(page[idxEvent].String1);
  212.                             break;
  213.                         case XmlEventType.StartContent:
  214.                            
  215.                             if (rawWriter != null)
  216.                                 rawWriter.StartElementContent();
  217.                             break;
  218.                         case XmlEventType.EndElem:
  219.                            
  220.                             if (rawWriter != null)
  221.                                 rawWriter.WriteEndElement(page[idxEvent].String1, page[idxEvent].String2, page[idxEvent].String3);
  222.                             else
  223.                                 writer.WriteEndElement();
  224.                             break;
  225.                         case XmlEventType.FullEndElem:
  226.                            
  227.                             if (rawWriter != null)
  228.                                 rawWriter.WriteFullEndElement(page[idxEvent].String1, page[idxEvent].String2, page[idxEvent].String3);
  229.                             else
  230.                                 writer.WriteFullEndElement();
  231.                             break;
  232.                         case XmlEventType.Nmsp:
  233.                            
  234.                             if (rawWriter != null)
  235.                                 rawWriter.WriteNamespaceDeclaration(page[idxEvent].String1, page[idxEvent].String2);
  236.                             else
  237.                                 writer.WriteAttributeString("xmlns", page[idxEvent].String1, XmlReservedNs.NsXmlNs, page[idxEvent].String2);
  238.                             break;
  239.                         case XmlEventType.EndBase64:
  240.                            
  241.                             if (rawWriter != null)
  242.                                 rawWriter.WriteEndBase64();
  243.                             break;
  244.                         case XmlEventType.Close:
  245.                            
  246.                             writer.Close();
  247.                             break;
  248.                         case XmlEventType.Flush:
  249.                            
  250.                             writer.Flush();
  251.                             break;
  252.                         case XmlEventType.Dispose:
  253.                            
  254.                             ((IDisposable)writer).Dispose();
  255.                             break;
  256.                         default:
  257.                            
  258.                             Debug.Assert(false, "Unknown event: " + page[idxEvent].EventType);
  259.                             break;
  260.                     }
  261.                 }
  262.             }
  263.            
  264.             Debug.Assert(false, "Unknown event should be added to end of event sequence.");
  265.         }
  266.        
  267.         /// <summary>
  268.         /// Concatenate all element text and atomic value events and return the resulting string.
  269.         /// </summary>
  270.         public string EventsToString()
  271.         {
  272.             StringBuilder bldr;
  273.             XmlEvent[] page;
  274.             int idxPage;
  275.             int idxEvent;
  276.             bool inAttr;
  277.            
  278.             // Special-case single text node at the top-level
  279.             if (this.singleText != null)
  280.                 return this.singleText;
  281.            
  282.             bldr = new StringBuilder();
  283.            
  284.             // Loop over set of pages
  285.             inAttr = false;
  286.             for (idxPage = 0; idxPage < this.pages.Count; idxPage++) {
  287.                 page = this.pages[idxPage] as XmlEvent[];
  288.                
  289.                 // Loop over events in each page
  290.                 for (idxEvent = 0; idxEvent < page.Length; idxEvent++) {
  291.                     switch (page[idxEvent].EventType) {
  292.                         case XmlEventType.Unknown:
  293.                             // No more events
  294.                             Debug.Assert(idxPage + 1 == this.pages.Count);
  295.                             return bldr.ToString();
  296.                         case XmlEventType.String:
  297.                         case XmlEventType.Whitespace:
  298.                         case XmlEventType.Raw:
  299.                         case XmlEventType.CData:
  300.                            
  301.                             // Append text
  302.                             if (!inAttr)
  303.                                 bldr.Append(page[idxEvent].String1);
  304.                             break;
  305.                         case XmlEventType.StartAttr:
  306.                            
  307.                             // Don't append text or atomic values if they appear within attributes
  308.                             inAttr = true;
  309.                             break;
  310.                         case XmlEventType.EndAttr:
  311.                            
  312.                             // No longer in an attribute
  313.                             inAttr = false;
  314.                             break;
  315.                     }
  316.                 }
  317.             }
  318.            
  319.             Debug.Assert(false, "Unknown event should be added to end of event sequence.");
  320.             return string.Empty;
  321.         }
  322.        
  323.        
  324.         //-----------------------------------------------
  325.         // XmlWriter interface
  326.         //-----------------------------------------------
  327.        
  328.         public override XmlWriterSettings Settings {
  329.             get { return null; }
  330.         }
  331.        
  332.         public override void WriteDocType(string name, string pubid, string sysid, string subset)
  333.         {
  334.             AddEvent(XmlEventType.DocType, name, pubid, sysid, subset);
  335.         }
  336.        
  337.         public override void WriteStartElement(string prefix, string localName, string ns)
  338.         {
  339.             AddEvent(XmlEventType.StartElem, prefix, localName, ns);
  340.         }
  341.        
  342.         public override void WriteStartAttribute(string prefix, string localName, string ns)
  343.         {
  344.             AddEvent(XmlEventType.StartAttr, prefix, localName, ns);
  345.         }
  346.        
  347.         public override void WriteEndAttribute()
  348.         {
  349.             AddEvent(XmlEventType.EndAttr);
  350.         }
  351.        
  352.         public override void WriteCData(string text)
  353.         {
  354.             AddEvent(XmlEventType.CData, text);
  355.         }
  356.        
  357.         public override void WriteComment(string text)
  358.         {
  359.             AddEvent(XmlEventType.Comment, text);
  360.         }
  361.        
  362.         public override void WriteProcessingInstruction(string name, string text)
  363.         {
  364.             AddEvent(XmlEventType.PI, name, text);
  365.         }
  366.        
  367.         public override void WriteWhitespace(string ws)
  368.         {
  369.             AddEvent(XmlEventType.Whitespace, ws);
  370.         }
  371.        
  372.         public override void WriteString(string text)
  373.         {
  374.             // Special-case single text node at the top level
  375.             if (this.pages == null) {
  376.                 if (this.singleText == null)
  377.                     this.singleText = text;
  378.                 else
  379.                     this.singleText += text;
  380.             }
  381.             else {
  382.                 AddEvent(XmlEventType.String, text);
  383.             }
  384.         }
  385.        
  386.         public override void WriteChars(char[] buffer, int index, int count)
  387.         {
  388.             WriteString(new string(buffer, index, count));
  389.         }
  390.        
  391.         public override void WriteRaw(char[] buffer, int index, int count)
  392.         {
  393.             WriteRaw(new string(buffer, index, count));
  394.         }
  395.        
  396.         public override void WriteRaw(string data)
  397.         {
  398.             AddEvent(XmlEventType.Raw, data);
  399.         }
  400.        
  401.         public override void WriteEntityRef(string name)
  402.         {
  403.             AddEvent(XmlEventType.EntRef, name);
  404.         }
  405.        
  406.         public override void WriteCharEntity(char ch)
  407.         {
  408.             AddEvent(XmlEventType.CharEnt, (object)ch);
  409.         }
  410.        
  411.         public override void WriteSurrogateCharEntity(char lowChar, char highChar)
  412.         {
  413.             // Save high and low characters
  414.             char[] chars = {lowChar, highChar};
  415.             AddEvent(XmlEventType.SurrCharEnt, (object)chars);
  416.         }
  417.        
  418.         public override void WriteBase64(byte[] buffer, int index, int count)
  419.         {
  420.             AddEvent(XmlEventType.Base64, (object)ToBytes(buffer, index, count));
  421.         }
  422.        
  423.         public override void WriteBinHex(byte[] buffer, int index, int count)
  424.         {
  425.             AddEvent(XmlEventType.BinHex, (object)ToBytes(buffer, index, count));
  426.         }
  427.        
  428.         public override void Close()
  429.         {
  430.             AddEvent(XmlEventType.Close);
  431.         }
  432.        
  433.         public override void Flush()
  434.         {
  435.             AddEvent(XmlEventType.Flush);
  436.         }
  437.        
  438.         /// <summary>
  439.         /// All other WriteValue methods are implemented by XmlWriter to delegate to WriteValue(object) or WriteValue(string), so
  440.         /// only these two methods need to be implemented.
  441.         /// </summary>
  442.         public override void WriteValue(object value)
  443.         {
  444.             WriteString(XmlUntypedConverter.Untyped.ToString(value, this.resolver));
  445.         }
  446.        
  447.         public override void WriteValue(string value)
  448.         {
  449.             WriteString(value);
  450.         }
  451.        
  452.         protected override void Dispose(bool disposing)
  453.         {
  454.             try {
  455.                 AddEvent(XmlEventType.Dispose);
  456.             }
  457.             finally {
  458.                 base.Dispose(disposing);
  459.             }
  460.         }
  461.        
  462.        
  463.         //-----------------------------------------------
  464.         // XmlRawWriter interface
  465.         //-----------------------------------------------
  466.        
  467.         internal override void WriteXmlDeclaration(XmlStandalone standalone)
  468.         {
  469.             AddEvent(XmlEventType.XmlDecl1, (object)standalone);
  470.         }
  471.        
  472.         internal override void WriteXmlDeclaration(string xmldecl)
  473.         {
  474.             AddEvent(XmlEventType.XmlDecl2, xmldecl);
  475.         }
  476.        
  477.         internal override void StartElementContent()
  478.         {
  479.             AddEvent(XmlEventType.StartContent);
  480.         }
  481.        
  482.         internal override void WriteEndElement(string prefix, string localName, string ns)
  483.         {
  484.             AddEvent(XmlEventType.EndElem, prefix, localName, ns);
  485.         }
  486.        
  487.         internal override void WriteFullEndElement(string prefix, string localName, string ns)
  488.         {
  489.             AddEvent(XmlEventType.FullEndElem, prefix, localName, ns);
  490.         }
  491.        
  492.         internal override void WriteNamespaceDeclaration(string prefix, string ns)
  493.         {
  494.             AddEvent(XmlEventType.Nmsp, prefix, ns);
  495.         }
  496.        
  497.         internal override void WriteEndBase64()
  498.         {
  499.             AddEvent(XmlEventType.EndBase64);
  500.         }
  501.        
  502.        
  503.         //-----------------------------------------------
  504.         // Helper methods
  505.         //-----------------------------------------------
  506.        
  507.         private void AddEvent(XmlEventType eventType)
  508.         {
  509.             int idx = NewEvent();
  510.             this.pageCurr[idx].InitEvent(eventType);
  511.         }
  512.        
  513.         private void AddEvent(XmlEventType eventType, string s1)
  514.         {
  515.             int idx = NewEvent();
  516.             this.pageCurr[idx].InitEvent(eventType, s1);
  517.         }
  518.        
  519.         private void AddEvent(XmlEventType eventType, string s1, string s2)
  520.         {
  521.             int idx = NewEvent();
  522.             this.pageCurr[idx].InitEvent(eventType, s1, s2);
  523.         }
  524.        
  525.         private void AddEvent(XmlEventType eventType, string s1, string s2, string s3)
  526.         {
  527.             int idx = NewEvent();
  528.             this.pageCurr[idx].InitEvent(eventType, s1, s2, s3);
  529.         }
  530.        
  531.         private void AddEvent(XmlEventType eventType, string s1, string s2, string s3, object o)
  532.         {
  533.             int idx = NewEvent();
  534.             this.pageCurr[idx].InitEvent(eventType, s1, s2, s3, o);
  535.         }
  536.        
  537.         private void AddEvent(XmlEventType eventType, object o)
  538.         {
  539.             int idx = NewEvent();
  540.             this.pageCurr[idx].InitEvent(eventType, o);
  541.         }
  542.        
  543.         private int NewEvent()
  544.         {
  545.             if (this.pages == null) {
  546.                 this.pages = new ArrayList();
  547.                 this.pageCurr = new XmlEvent[InitialPageSize];
  548.                 this.pages.Add(this.pageCurr);
  549.                
  550.                 if (this.singleText != null) {
  551.                     this.pageCurr[0].InitEvent(XmlEventType.String, this.singleText);
  552.                     this.pageSize++;
  553.                     this.singleText = null;
  554.                 }
  555.             }
  556.             else if (this.pageSize >= this.pageCurr.Length) {
  557.                 // Create new page
  558.                 this.pageCurr = new XmlEvent[this.pageSize * 2];
  559.                 this.pages.Add(this.pageCurr);
  560.                 this.pageSize = 0;
  561.             }
  562.            
  563.             return this.pageSize++;
  564.         }
  565.        
  566.         /// <summary>
  567.         /// Create a standalone buffer that doesn't need an index or count passed along with it.
  568.         /// </summary>
  569.         private static byte[] ToBytes(byte[] buffer, int index, int count)
  570.         {
  571.             if (index != 0 || count != buffer.Length) {
  572.                 if (buffer.Length - index > count)
  573.                     count = buffer.Length - index;
  574.                
  575.                 byte[] bufferNew = new byte[count];
  576.                 Array.Copy(buffer, index, bufferNew, 0, count);
  577.                
  578.                 return bufferNew;
  579.             }
  580.            
  581.             return buffer;
  582.         }
  583.        
  584.        
  585.         /// <summary>
  586.         /// Caches information for XML events like BeginElement, String, and EndAttribute so that they can be replayed later.
  587.         /// </summary>
  588.         private struct XmlEvent
  589.         {
  590.             private XmlEventType eventType;
  591.             private string s1;
  592.             private string s2;
  593.             private string s3;
  594.             private object o;
  595.            
  596.             public void InitEvent(XmlEventType eventType)
  597.             {
  598.                 this.eventType = eventType;
  599.             }
  600.            
  601.             public void InitEvent(XmlEventType eventType, string s1)
  602.             {
  603.                 this.eventType = eventType;
  604.                 this.s1 = s1;
  605.             }
  606.            
  607.             public void InitEvent(XmlEventType eventType, string s1, string s2)
  608.             {
  609.                 this.eventType = eventType;
  610.                 this.s1 = s1;
  611.                 this.s2 = s2;
  612.             }
  613.            
  614.             public void InitEvent(XmlEventType eventType, string s1, string s2, string s3)
  615.             {
  616.                 this.eventType = eventType;
  617.                 this.s1 = s1;
  618.                 this.s2 = s2;
  619.                 this.s3 = s3;
  620.             }
  621.            
  622.             public void InitEvent(XmlEventType eventType, string s1, string s2, string s3, object o)
  623.             {
  624.                 this.eventType = eventType;
  625.                 this.s1 = s1;
  626.                 this.s2 = s2;
  627.                 this.s3 = s3;
  628.                 this.o = o;
  629.             }
  630.            
  631.             public void InitEvent(XmlEventType eventType, object o)
  632.             {
  633.                 this.eventType = eventType;
  634.                 this.o = o;
  635.             }
  636.            
  637.             public XmlEventType EventType {
  638.                 get { return this.eventType; }
  639.             }
  640.            
  641.             public string String1 {
  642.                 get { return this.s1; }
  643.             }
  644.            
  645.             public string String2 {
  646.                 get { return this.s2; }
  647.             }
  648.            
  649.             public string String3 {
  650.                 get { return this.s3; }
  651.             }
  652.            
  653.             public object Object {
  654.                 get { return this.o; }
  655.             }
  656.         }
  657.     }
  658. }

Developer Fusion