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