File: WhitespaceRuleLookup.cs

package info (click to toggle)
mono 6.14.1%2Bds2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,282,732 kB
  • sloc: cs: 11,182,461; xml: 2,850,281; ansic: 699,123; cpp: 122,919; perl: 58,604; javascript: 30,841; asm: 21,845; makefile: 19,602; sh: 10,973; python: 4,772; pascal: 925; sql: 859; sed: 16; php: 1
file content (166 lines) | stat: -rw-r--r-- 7,281 bytes parent folder | download | duplicates (6)
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;
            }
        }
    }
}