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: TemplatesHandlerImpl.java 577935 2007-09-20 21:35:20Z minchau $ 020 */ 021 022 package org.apache.xalan.xsltc.trax; 023 024 import javax.xml.XMLConstants; 025 import javax.xml.transform.Source; 026 import javax.xml.transform.Templates; 027 import javax.xml.transform.TransformerException; 028 import javax.xml.transform.URIResolver; 029 import javax.xml.transform.sax.TemplatesHandler; 030 031 import org.apache.xalan.xsltc.compiler.CompilerException; 032 import org.apache.xalan.xsltc.compiler.Parser; 033 import org.apache.xalan.xsltc.compiler.SourceLoader; 034 import org.apache.xalan.xsltc.compiler.Stylesheet; 035 import org.apache.xalan.xsltc.compiler.SyntaxTreeNode; 036 import org.apache.xalan.xsltc.compiler.XSLTC; 037 import org.apache.xalan.xsltc.compiler.util.ErrorMsg; 038 039 import org.xml.sax.ContentHandler; 040 import org.xml.sax.InputSource; 041 import org.xml.sax.Locator; 042 import org.xml.sax.SAXException; 043 import org.xml.sax.Attributes; 044 045 import java.util.Vector; 046 047 /** 048 * Implementation of a JAXP1.1 TemplatesHandler 049 * @author Morten Jorgensen 050 * @author Santiago Pericas-Geertsen 051 */ 052 public class TemplatesHandlerImpl 053 implements ContentHandler, TemplatesHandler, SourceLoader 054 { 055 /** 056 * System ID for this stylesheet. 057 */ 058 private String _systemId; 059 060 /** 061 * Number of spaces to add for output indentation. 062 */ 063 private int _indentNumber; 064 065 /** 066 * This URIResolver is passed to all Transformers. 067 */ 068 private URIResolver _uriResolver = null; 069 070 /** 071 * A reference to the transformer factory that this templates 072 * object belongs to. 073 */ 074 private TransformerFactoryImpl _tfactory = null; 075 076 /** 077 * A reference to XSLTC's parser object. 078 */ 079 private Parser _parser = null; 080 081 /** 082 * The created Templates object. 083 */ 084 private TemplatesImpl _templates = null; 085 086 /** 087 * Default constructor 088 */ 089 protected TemplatesHandlerImpl(int indentNumber, 090 TransformerFactoryImpl tfactory) 091 { 092 _indentNumber = indentNumber; 093 _tfactory = tfactory; 094 095 // Instantiate XSLTC and get reference to parser object 096 XSLTC xsltc = new XSLTC(); 097 if (tfactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING)) 098 xsltc.setSecureProcessing(true); 099 100 if ("true".equals(tfactory.getAttribute(TransformerFactoryImpl.ENABLE_INLINING))) 101 xsltc.setTemplateInlining(true); 102 else 103 xsltc.setTemplateInlining(false); 104 105 _parser = xsltc.getParser(); 106 } 107 108 /** 109 * Implements javax.xml.transform.sax.TemplatesHandler.getSystemId() 110 * Get the base ID (URI or system ID) from where relative URLs will be 111 * resolved. 112 * @return The systemID that was set with setSystemId(String id) 113 */ 114 public String getSystemId() { 115 return _systemId; 116 } 117 118 /** 119 * Implements javax.xml.transform.sax.TemplatesHandler.setSystemId() 120 * Get the base ID (URI or system ID) from where relative URLs will be 121 * resolved. 122 * @param id Base URI for this stylesheet 123 */ 124 public void setSystemId(String id) { 125 _systemId = id; 126 } 127 128 /** 129 * Store URIResolver needed for Transformers. 130 */ 131 public void setURIResolver(URIResolver resolver) { 132 _uriResolver = resolver; 133 } 134 135 /** 136 * Implements javax.xml.transform.sax.TemplatesHandler.getTemplates() 137 * When a TemplatesHandler object is used as a ContentHandler or 138 * DocumentHandler for the parsing of transformation instructions, it 139 * creates a Templates object, which the caller can get once the SAX 140 * events have been completed. 141 * @return The Templates object that was created during the SAX event 142 * process, or null if no Templates object has been created. 143 */ 144 public Templates getTemplates() { 145 return _templates; 146 } 147 148 /** 149 * This method implements XSLTC's SourceLoader interface. It is used to 150 * glue a TrAX URIResolver to the XSLTC compiler's Input and Import classes. 151 * 152 * @param href The URI of the document to load 153 * @param context The URI of the currently loaded document 154 * @param xsltc The compiler that resuests the document 155 * @return An InputSource with the loaded document 156 */ 157 public InputSource loadSource(String href, String context, XSLTC xsltc) { 158 try { 159 // A _uriResolver must be set if this method is called 160 final Source source = _uriResolver.resolve(href, context); 161 if (source != null) { 162 return Util.getInputSource(xsltc, source); 163 } 164 } 165 catch (TransformerException e) { 166 // Falls through 167 } 168 return null; 169 } 170 171 // -- ContentHandler -------------------------------------------------- 172 173 /** 174 * Re-initialize parser and forward SAX2 event. 175 */ 176 public void startDocument() { 177 XSLTC xsltc = _parser.getXSLTC(); 178 xsltc.init(); // calls _parser.init() 179 xsltc.setOutputType(XSLTC.BYTEARRAY_OUTPUT); 180 _parser.startDocument(); 181 } 182 183 /** 184 * Just forward SAX2 event to parser object. 185 */ 186 public void endDocument() throws SAXException { 187 _parser.endDocument(); 188 189 // create the templates 190 try { 191 XSLTC xsltc = _parser.getXSLTC(); 192 193 // Set the translet class name if not already set 194 String transletName; 195 if (_systemId != null) { 196 transletName = Util.baseName(_systemId); 197 } 198 else { 199 transletName = (String)_tfactory.getAttribute("translet-name"); 200 } 201 xsltc.setClassName(transletName); 202 203 // Get java-legal class name from XSLTC module 204 transletName = xsltc.getClassName(); 205 206 Stylesheet stylesheet = null; 207 SyntaxTreeNode root = _parser.getDocumentRoot(); 208 209 // Compile the translet - this is where the work is done! 210 if (!_parser.errorsFound() && root != null) { 211 // Create a Stylesheet element from the root node 212 stylesheet = _parser.makeStylesheet(root); 213 stylesheet.setSystemId(_systemId); 214 stylesheet.setParentStylesheet(null); 215 216 if (xsltc.getTemplateInlining()) 217 stylesheet.setTemplateInlining(true); 218 else 219 stylesheet.setTemplateInlining(false); 220 221 // Set a document loader (for xsl:include/import) if defined 222 if (_uriResolver != null) { 223 stylesheet.setSourceLoader(this); 224 } 225 226 _parser.setCurrentStylesheet(stylesheet); 227 228 // Set it as top-level in the XSLTC object 229 xsltc.setStylesheet(stylesheet); 230 231 // Create AST under the Stylesheet element 232 _parser.createAST(stylesheet); 233 } 234 235 // Generate the bytecodes and output the translet class(es) 236 if (!_parser.errorsFound() && stylesheet != null) { 237 stylesheet.setMultiDocument(xsltc.isMultiDocument()); 238 stylesheet.setHasIdCall(xsltc.hasIdCall()); 239 240 // Class synchronization is needed for BCEL 241 synchronized (xsltc.getClass()) { 242 stylesheet.translate(); 243 } 244 } 245 246 if (!_parser.errorsFound()) { 247 // Check that the transformation went well before returning 248 final byte[][] bytecodes = xsltc.getBytecodes(); 249 if (bytecodes != null) { 250 _templates = 251 new TemplatesImpl(xsltc.getBytecodes(), transletName, 252 _parser.getOutputProperties(), _indentNumber, _tfactory); 253 254 // Set URIResolver on templates object 255 if (_uriResolver != null) { 256 _templates.setURIResolver(_uriResolver); 257 } 258 } 259 } 260 else { 261 StringBuffer errorMessage = new StringBuffer(); 262 Vector errors = _parser.getErrors(); 263 final int count = errors.size(); 264 for (int i = 0; i < count; i++) { 265 if (errorMessage.length() > 0) 266 errorMessage.append('\n'); 267 errorMessage.append(errors.elementAt(i).toString()); 268 } 269 throw new SAXException(ErrorMsg.JAXP_COMPILE_ERR, new TransformerException(errorMessage.toString())); 270 } 271 } 272 catch (CompilerException e) { 273 throw new SAXException(ErrorMsg.JAXP_COMPILE_ERR, e); 274 } 275 } 276 277 /** 278 * Just forward SAX2 event to parser object. 279 */ 280 public void startPrefixMapping(String prefix, String uri) { 281 _parser.startPrefixMapping(prefix, uri); 282 } 283 284 /** 285 * Just forward SAX2 event to parser object. 286 */ 287 public void endPrefixMapping(String prefix) { 288 _parser.endPrefixMapping(prefix); 289 } 290 291 /** 292 * Just forward SAX2 event to parser object. 293 */ 294 public void startElement(String uri, String localname, String qname, 295 Attributes attributes) throws SAXException 296 { 297 _parser.startElement(uri, localname, qname, attributes); 298 } 299 300 /** 301 * Just forward SAX2 event to parser object. 302 */ 303 public void endElement(String uri, String localname, String qname) { 304 _parser.endElement(uri, localname, qname); 305 } 306 307 /** 308 * Just forward SAX2 event to parser object. 309 */ 310 public void characters(char[] ch, int start, int length) { 311 _parser.characters(ch, start, length); 312 } 313 314 /** 315 * Just forward SAX2 event to parser object. 316 */ 317 public void processingInstruction(String name, String value) { 318 _parser.processingInstruction(name, value); 319 } 320 321 /** 322 * Just forward SAX2 event to parser object. 323 */ 324 public void ignorableWhitespace(char[] ch, int start, int length) { 325 _parser.ignorableWhitespace(ch, start, length); 326 } 327 328 /** 329 * Just forward SAX2 event to parser object. 330 */ 331 public void skippedEntity(String name) { 332 _parser.skippedEntity(name); 333 } 334 335 /** 336 * Set internal system Id and forward SAX2 event to parser object. 337 */ 338 public void setDocumentLocator(Locator locator) { 339 setSystemId(locator.getSystemId()); 340 _parser.setDocumentLocator(locator); 341 } 342 } 343 344