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

  1. //------------------------------------------------------------------------------
  2. // <copyright file="WhitespaceRuleLookup.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.Xml;
  17. using System.Collections;
  18. using System.Collections.Generic;
  19. using System.Diagnostics;
  20. using MS.Internal.Xml;
  21. using System.Xml.Xsl.Qil;
  22. namespace System.Xml.Xsl.Runtime
  23. {
  24.    
  25.     /// <summary>
  26.     /// This class keeps a list of whitespace rules in order to determine whether whitespace children of particular
  27.     /// elements should be stripped.
  28.     /// </summary>
  29.     internal class WhitespaceRuleLookup
  30.     {
  31.         private Hashtable qnames;
  32.         private ArrayList wildcards;
  33.         private InternalWhitespaceRule ruleTemp;
  34.         private XmlNameTable nameTable;
  35.        
  36.         public WhitespaceRuleLookup()
  37.         {
  38.             this.qnames = new Hashtable();
  39.             this.wildcards = new ArrayList();
  40.         }
  41.        
  42.         /// <summary>
  43.         /// Create a new lookup internal class from the specified WhitespaceRules. Use the name table to atomize all
  44.         /// names for fast comparison.
  45.         /// </summary>
  46.         public WhitespaceRuleLookup(IList<WhitespaceRule> rules) : this()
  47.         {
  48.             WhitespaceRule rule;
  49.             InternalWhitespaceRule ruleInternal;
  50.             Debug.Assert(rules != null);
  51.            
  52.             for (int i = rules.Count - 1; i >= 0; i--) {
  53.                 // Make a copy of each rule, but atomize each name
  54.                 rule = rules[i];
  55.                 ruleInternal = new InternalWhitespaceRule(rule.LocalName, rule.NamespaceName, rule.PreserveSpace, -i);
  56.                
  57.                 if (rule.LocalName == null || rule.NamespaceName == null) {
  58.                     // Wildcard, so add to wildcards array
  59.                     this.wildcards.Add(ruleInternal);
  60.                 }
  61.                 else {
  62.                     // Exact name, so add to hashtable
  63.                     this.qnames[ruleInternal] = ruleInternal;
  64.                 }
  65.             }
  66.            
  67.             // Create a temporary (not thread-safe) InternalWhitespaceRule used for lookups
  68.             this.ruleTemp = new InternalWhitespaceRule();
  69.         }
  70.        
  71.         /// <summary>
  72.         /// Atomize all names contained within the whitespace rules with respect to "nameTable".
  73.         /// </summary>
  74.         public void Atomize(XmlNameTable nameTable)
  75.         {
  76.             // If names are already atomized with respect to "nameTable", no need to do it again
  77.             if (nameTable != this.nameTable) {
  78.                 this.nameTable = nameTable;
  79.                
  80.                 foreach (InternalWhitespaceRule rule in this.qnames.Values)
  81.                     rule.Atomize(nameTable);
  82.                
  83.                 foreach (InternalWhitespaceRule rule in this.wildcards)
  84.                     rule.Atomize(nameTable);
  85.             }
  86.         }
  87.        
  88.         /// <summary>
  89.         /// Return true if elements of the specified name should have whitespace children stripped.
  90.         /// NOTE: This method is not thread-safe. Different threads should create their own copy of the
  91.         /// WhitespaceRuleLookup object. This allows all names to be atomized according to a private NameTable.
  92.         /// </summary>
  93.         public bool ShouldStripSpace(string localName, string namespaceName)
  94.         {
  95.             InternalWhitespaceRule qnameRule;
  96.             InternalWhitespaceRule wildcardRule;
  97.             Debug.Assert(this.nameTable != null && this.ruleTemp != null);
  98.             Debug.Assert(localName != null && (object)this.nameTable.Get(localName) == (object)localName);
  99.             Debug.Assert(namespaceName != null && (object)this.nameTable.Get(namespaceName) == (object)namespaceName);
  100.            
  101.             this.ruleTemp.Init(localName, namespaceName, false, 0);
  102.            
  103.             // Lookup name in qnames table
  104.             // If found, the name will be stripped unless there is a preserve wildcard with higher priority
  105.             qnameRule = this.qnames[this.ruleTemp] as InternalWhitespaceRule;
  106.            
  107.             for (int pos = this.wildcards.Count; pos-- != 0;) {
  108.                 wildcardRule = this.wildcards[pos] as InternalWhitespaceRule;
  109.                
  110.                 if (qnameRule != null) {
  111.                     // If qname priority is greater than any subsequent wildcard's priority, then we're done
  112.                     if (qnameRule.Priority > wildcardRule.Priority)
  113.                         return !qnameRule.PreserveSpace;
  114.                    
  115.                     if (qnameRule.PreserveSpace == wildcardRule.PreserveSpace)
  116.                         continue;
  117.                 }
  118.                
  119.                 if (wildcardRule.LocalName == null || (object)wildcardRule.LocalName == (object)localName) {
  120.                     if (wildcardRule.NamespaceName == null || (object)wildcardRule.NamespaceName == (object)namespaceName) {
  121.                         // Found wildcard match, so we're done (since wildcards are in priority order)
  122.                         return !wildcardRule.PreserveSpace;
  123.                     }
  124.                 }
  125.             }
  126.            
  127.             return (qnameRule != null && !qnameRule.PreserveSpace);
  128.         }
  129.        
  130.         private class InternalWhitespaceRule : WhitespaceRule
  131.         {
  132.             private int priority;
  133.             // Relative priority of this test
  134.             private int hashCode;
  135.             // Cached hashcode
  136.             public InternalWhitespaceRule()
  137.             {
  138.             }
  139.            
  140.             public InternalWhitespaceRule(string localName, string namespaceName, bool preserveSpace, int priority)
  141.             {
  142.                 Init(localName, namespaceName, preserveSpace, priority);
  143.             }
  144.            
  145.             public void Init(string localName, string namespaceName, bool preserveSpace, int priority)
  146.             {
  147.                 base.Init(localName, namespaceName, preserveSpace);
  148.                 this.priority = priority;
  149.                
  150.                 if (localName != null && namespaceName != null) {
  151.                     this.hashCode = localName.GetHashCode();
  152.                 }
  153.             }
  154.            
  155.             public void Atomize(XmlNameTable nameTable)
  156.             {
  157.                 if (LocalName != null)
  158.                     LocalName = nameTable.Add(LocalName);
  159.                
  160.                 if (NamespaceName != null)
  161.                     NamespaceName = nameTable.Add(NamespaceName);
  162.             }
  163.            
  164.             public int Priority {
  165.                 get { return this.priority; }
  166.             }
  167.            
  168.             public override int GetHashCode()
  169.             {
  170.                 return this.hashCode;
  171.             }
  172.            
  173.             public override bool Equals(object obj)
  174.             {
  175.                 Debug.Assert(obj is InternalWhitespaceRule);
  176.                 InternalWhitespaceRule that = obj as InternalWhitespaceRule;
  177.                
  178.                 Debug.Assert(LocalName != null && that.LocalName != null);
  179.                 Debug.Assert(NamespaceName != null && that.NamespaceName != null);
  180.                 return (object)LocalName == (object)LocalName && (object)NamespaceName == (object)that.NamespaceName;
  181.             }
  182.         }
  183.     }
  184. }

Developer Fusion