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