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