The Labs \ Source Viewer \ SSCLI \ System.Xml.Xsl.Runtime \ WhitespaceRuleReader

  1. //------------------------------------------------------------------------------
  2. // <copyright file="WhitespaceRuleReader.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. using System;
  16. using System.IO;
  17. using System.Xml;
  18. using System.Xml.Schema;
  19. using System.Diagnostics;
  20. using MS.Internal.Xml;
  21. namespace System.Xml.Xsl.Runtime
  22. {
  23.    
  24.     /// <summary>
  25.     /// </summary>
  26.     internal class WhitespaceRuleReader : XmlWrappingReader
  27.     {
  28.         private WhitespaceRuleLookup wsRules;
  29.         private BitStack stkStrip;
  30.         private bool shouldStrip, preserveAdjacent;
  31.         private string val;
  32.         private XmlCharType xmlCharType = XmlCharType.Instance;
  33.        
  34.         public static XmlReader CreateReader(XmlReader baseReader, WhitespaceRuleLookup wsRules)
  35.         {
  36.             if (wsRules == null) {
  37.                 return baseReader;
  38.                 // There is no rules to process
  39.             }
  40.             XmlReaderSettings readerSettings = baseReader.Settings;
  41.             if (readerSettings != null) {
  42.                 if (readerSettings.IgnoreWhitespace) {
  43.                     return baseReader;
  44.                     // V2 XmlReader that strips all WS
  45.                 }
  46.             }
  47.             else {
  48.                 XmlTextReader txtReader = baseReader as XmlTextReader;
  49.                 if (txtReader != null && txtReader.WhitespaceHandling == WhitespaceHandling.None) {
  50.                     return baseReader;
  51.                     // V1 XmlTextReader that strips all WS
  52.                 }
  53.                 XmlTextReaderImpl txtReaderImpl = baseReader as XmlTextReaderImpl;
  54.                 if (txtReaderImpl != null && txtReaderImpl.WhitespaceHandling == WhitespaceHandling.None) {
  55.                     return baseReader;
  56.                     // XmlTextReaderImpl that strips all WS
  57.                 }
  58.             }
  59.             return new WhitespaceRuleReader(baseReader, wsRules);
  60.         }
  61.        
  62.         private WhitespaceRuleReader(XmlReader baseReader, WhitespaceRuleLookup wsRules) : base(baseReader)
  63.         {
  64.             Debug.Assert(wsRules != null);
  65.            
  66.             this.val = null;
  67.             this.stkStrip = new BitStack();
  68.             this.shouldStrip = false;
  69.             this.preserveAdjacent = false;
  70.            
  71.             this.wsRules = wsRules;
  72.             this.wsRules.Atomize(baseReader.NameTable);
  73.         }
  74.        
  75.         /// <summary>
  76.         /// Override Value in order to possibly prepend extra whitespace.
  77.         /// </summary>
  78.         public override string Value {
  79.             get { return (this.val == null) ? base.Value : this.val; }
  80.         }
  81.        
  82.         /// <summary>
  83.         /// Override Read in order to search for strippable whitespace, to concatenate adjacent text nodes, and to
  84.         /// resolve entities.
  85.         /// </summary>
  86.         public override bool Read()
  87.         {
  88.             XmlCharType xmlCharType = XmlCharType.Instance;
  89.             string ws = null;
  90.            
  91.             // Clear text value
  92.             this.val = null;
  93.            
  94.             while (base.Read()) {
  95.                 switch (base.NodeType) {
  96.                     case XmlNodeType.Element:
  97.                         // Push boolean indicating whether whitespace children of this element should be stripped
  98.                         if (!base.IsEmptyElement) {
  99.                             this.stkStrip.PushBit(this.shouldStrip);
  100.                            
  101.                             // Strip if rules say we should and we're not within the scope of xml:space="preserve"
  102.                             this.shouldStrip = wsRules.ShouldStripSpace(base.LocalName, base.NamespaceURI) && (base.XmlSpace != XmlSpace.Preserve);
  103.                         }
  104.                         break;
  105.                     case XmlNodeType.EndElement:
  106.                        
  107.                         // Restore parent shouldStrip setting
  108.                         this.shouldStrip = this.stkStrip.PopBit();
  109.                         break;
  110.                     case XmlNodeType.Text:
  111.                     case XmlNodeType.CDATA:
  112.                        
  113.                         // If preserving adjacent text, don't perform any further checks
  114.                         if (this.preserveAdjacent)
  115.                             return true;
  116.                        
  117.                         if (this.shouldStrip) {
  118.                             // Reader may report whitespace as Text or CDATA
  119.                             if (xmlCharType.IsOnlyWhitespace(base.Value))
  120.                                 goto case XmlNodeType.Whitespace;
  121.                            
  122.                             // If whitespace was cached, then prepend it to text or CDATA value
  123.                             if (ws != null)
  124.                                 this.val = string.Concat(ws, base.Value);
  125.                            
  126.                             // Preserve adjacent whitespace
  127.                             this.preserveAdjacent = true;
  128.                             return true;
  129.                         }
  130.                         break;
  131.                     case XmlNodeType.Whitespace:
  132.                     case XmlNodeType.SignificantWhitespace:
  133.                        
  134.                         // If preserving adjacent text, don't perform any further checks
  135.                         if (this.preserveAdjacent)
  136.                             return true;
  137.                        
  138.                         if (this.shouldStrip) {
  139.                             // Save whitespace until it can be determined whether it will be stripped
  140.                             if (ws == null)
  141.                                 ws = base.Value;
  142.                             else
  143.                                 ws = string.Concat(ws, base.Value);
  144.                            
  145.                             // Read next event
  146.                             continue;
  147.                         }
  148.                         break;
  149.                     case XmlNodeType.EntityReference:
  150.                         reader.ResolveEntity();
  151.                         break;
  152.                     case XmlNodeType.EndEntity:
  153.                         // Read next event
  154.                         continue;
  155.                 }
  156.                
  157.                 // No longer preserve adjacent space
  158.                 this.preserveAdjacent = false;
  159.                 return true;
  160.             }
  161.            
  162.             return false;
  163.         }
  164.     }
  165. }

Developer Fusion