001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 /*
019 * $Id: SymbolTable.java 669373 2008-06-19 03:40:20Z zongaro $
020 */
021
022 package org.apache.xalan.xsltc.compiler;
023
024 import java.util.Hashtable;
025 import java.util.Stack;
026 import java.util.StringTokenizer;
027 import java.util.Vector;
028
029 import org.apache.xalan.xsltc.compiler.util.MethodType;
030
031 /**
032 * @author Jacek Ambroziak
033 * @author Santiago Pericas-Geertsen
034 * @author Morten Jorgensen
035 */
036 final class SymbolTable {
037
038 // These hashtables are used for all stylesheets
039 private final Hashtable _stylesheets = new Hashtable();
040 private final Hashtable _primops = new Hashtable();
041
042 // These hashtables are used for some stylesheets
043 private Hashtable _variables = null;
044 private Hashtable _templates = null;
045 private Hashtable _attributeSets = null;
046 private Hashtable _aliases = null;
047 private Hashtable _excludedURI = null;
048 private Stack _excludedURIStack = null;
049 private Hashtable _decimalFormats = null;
050 private Hashtable _keys = null;
051
052 public DecimalFormatting getDecimalFormatting(QName name) {
053 if (_decimalFormats == null) return null;
054 return((DecimalFormatting)_decimalFormats.get(name));
055 }
056
057 public void addDecimalFormatting(QName name, DecimalFormatting symbols) {
058 if (_decimalFormats == null) _decimalFormats = new Hashtable();
059 _decimalFormats.put(name, symbols);
060 }
061
062 public Key getKey(QName name) {
063 if (_keys == null) return null;
064 return (Key) _keys.get(name);
065 }
066
067 public void addKey(QName name, Key key) {
068 if (_keys == null) _keys = new Hashtable();
069 _keys.put(name, key);
070 }
071
072 public Stylesheet addStylesheet(QName name, Stylesheet node) {
073 return (Stylesheet)_stylesheets.put(name, node);
074 }
075
076 public Stylesheet lookupStylesheet(QName name) {
077 return (Stylesheet)_stylesheets.get(name);
078 }
079
080 public Template addTemplate(Template template) {
081 final QName name = template.getName();
082 if (_templates == null) _templates = new Hashtable();
083 return (Template)_templates.put(name, template);
084 }
085
086 public Template lookupTemplate(QName name) {
087 if (_templates == null) return null;
088 return (Template)_templates.get(name);
089 }
090
091 public Variable addVariable(Variable variable) {
092 if (_variables == null) _variables = new Hashtable();
093 final String name = variable.getName().getStringRep();
094 return (Variable)_variables.put(name, variable);
095 }
096
097 public Param addParam(Param parameter) {
098 if (_variables == null) _variables = new Hashtable();
099 final String name = parameter.getName().getStringRep();
100 return (Param)_variables.put(name, parameter);
101 }
102
103 public Variable lookupVariable(QName qname) {
104 if (_variables == null) return null;
105 final String name = qname.getStringRep();
106 final Object obj = _variables.get(name);
107 return obj instanceof Variable ? (Variable)obj : null;
108 }
109
110 public Param lookupParam(QName qname) {
111 if (_variables == null) return null;
112 final String name = qname.getStringRep();
113 final Object obj = _variables.get(name);
114 return obj instanceof Param ? (Param)obj : null;
115 }
116
117 public SyntaxTreeNode lookupName(QName qname) {
118 if (_variables == null) return null;
119 final String name = qname.getStringRep();
120 return (SyntaxTreeNode)_variables.get(name);
121 }
122
123 public AttributeSet addAttributeSet(AttributeSet atts) {
124 if (_attributeSets == null) _attributeSets = new Hashtable();
125 return (AttributeSet)_attributeSets.put(atts.getName(), atts);
126 }
127
128 public AttributeSet lookupAttributeSet(QName name) {
129 if (_attributeSets == null) return null;
130 return (AttributeSet)_attributeSets.get(name);
131 }
132
133 /**
134 * Add a primitive operator or function to the symbol table. To avoid
135 * name clashes with user-defined names, the prefix <tt>PrimopPrefix</tt>
136 * is prepended.
137 */
138 public void addPrimop(String name, MethodType mtype) {
139 Vector methods = (Vector)_primops.get(name);
140 if (methods == null) {
141 _primops.put(name, methods = new Vector());
142 }
143 methods.addElement(mtype);
144 }
145
146 /**
147 * Lookup a primitive operator or function in the symbol table by
148 * prepending the prefix <tt>PrimopPrefix</tt>.
149 */
150 public Vector lookupPrimop(String name) {
151 return (Vector)_primops.get(name);
152 }
153
154 /**
155 * This is used for xsl:attribute elements that have a "namespace"
156 * attribute that is currently not defined using xmlns:
157 */
158 private int _nsCounter = 0;
159
160 public String generateNamespacePrefix() {
161 return("ns"+(_nsCounter++));
162 }
163
164 /**
165 * Use a namespace prefix to lookup a namespace URI
166 */
167 private SyntaxTreeNode _current = null;
168
169 public void setCurrentNode(SyntaxTreeNode node) {
170 _current = node;
171 }
172
173 public String lookupNamespace(String prefix) {
174 if (_current == null) return(Constants.EMPTYSTRING);
175 return(_current.lookupNamespace(prefix));
176 }
177
178 /**
179 * Adds an alias for a namespace prefix
180 */
181 public void addPrefixAlias(String prefix, String alias) {
182 if (_aliases == null) _aliases = new Hashtable();
183 _aliases.put(prefix,alias);
184 }
185
186 /**
187 * Retrieves any alias for a given namespace prefix
188 */
189 public String lookupPrefixAlias(String prefix) {
190 if (_aliases == null) return null;
191 return (String)_aliases.get(prefix);
192 }
193
194 /**
195 * Register a namespace URI so that it will not be declared in the output
196 * unless it is actually referenced in the output.
197 */
198 public void excludeURI(String uri) {
199 // The null-namespace cannot be excluded
200 if (uri == null) return;
201
202 // Create new hashtable of exlcuded URIs if none exists
203 if (_excludedURI == null) _excludedURI = new Hashtable();
204
205 // Register the namespace URI
206 Integer refcnt = (Integer)_excludedURI.get(uri);
207 if (refcnt == null)
208 refcnt = new Integer(1);
209 else
210 refcnt = new Integer(refcnt.intValue() + 1);
211 _excludedURI.put(uri,refcnt);
212 }
213
214 /**
215 * Exclude a series of namespaces given by a list of whitespace
216 * separated namespace prefixes.
217 */
218 public void excludeNamespaces(String prefixes) {
219 if (prefixes != null) {
220 StringTokenizer tokens = new StringTokenizer(prefixes);
221 while (tokens.hasMoreTokens()) {
222 final String prefix = tokens.nextToken();
223 final String uri;
224 if (prefix.equals("#default"))
225 uri = lookupNamespace(Constants.EMPTYSTRING);
226 else
227 uri = lookupNamespace(prefix);
228 if (uri != null) excludeURI(uri);
229 }
230 }
231 }
232
233 /**
234 * Check if a namespace should not be declared in the output (unless used)
235 */
236 public boolean isExcludedNamespace(String uri) {
237 if (uri != null && _excludedURI != null) {
238 final Integer refcnt = (Integer)_excludedURI.get(uri);
239 return (refcnt != null && refcnt.intValue() > 0);
240 }
241 return false;
242 }
243
244 /**
245 * Turn of namespace declaration exclusion
246 */
247 public void unExcludeNamespaces(String prefixes) {
248 if (_excludedURI == null) return;
249 if (prefixes != null) {
250 StringTokenizer tokens = new StringTokenizer(prefixes);
251 while (tokens.hasMoreTokens()) {
252 final String prefix = tokens.nextToken();
253 final String uri;
254 if (prefix.equals("#default"))
255 uri = lookupNamespace(Constants.EMPTYSTRING);
256 else
257 uri = lookupNamespace(prefix);
258 Integer refcnt = (Integer)_excludedURI.get(uri);
259 if (refcnt != null)
260 _excludedURI.put(uri, new Integer(refcnt.intValue() - 1));
261 }
262 }
263 }
264
265 /**
266 * Exclusion of namespaces by a stylesheet does not extend to any stylesheet
267 * imported or included by the stylesheet. Upon entering the context of a
268 * new stylesheet, a call to this method is needed to clear the current set
269 * of excluded namespaces temporarily. Every call to this method requires
270 * a corresponding call to {@link #popExcludedNamespacesContext()}.
271 */
272 public void pushExcludedNamespacesContext() {
273 if (_excludedURIStack == null) {
274 _excludedURIStack = new Stack();
275 }
276 _excludedURIStack.push(_excludedURI);
277 _excludedURI = null;
278 }
279
280 /**
281 * Exclusion of namespaces by a stylesheet does not extend to any stylesheet
282 * imported or included by the stylesheet. Upon exiting the context of a
283 * stylesheet, a call to this method is needed to restore the set of
284 * excluded namespaces that was in effect prior to entering the context of
285 * the current stylesheet.
286 */
287 public void popExcludedNamespacesContext() {
288 _excludedURI = (Hashtable) _excludedURIStack.pop();
289 if (_excludedURIStack.isEmpty()) {
290 _excludedURIStack = null;
291 }
292 }
293
294 }
295