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