1. /*
  2. * Copyright 2001-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /*
  17. * $Id: TemplatesHandlerImpl.java,v 1.25 2004/02/16 22:57:21 minchau Exp $
  18. */
  19. package com.sun.org.apache.xalan.internal.xsltc.trax;
  20. import javax.xml.transform.Source;
  21. import javax.xml.transform.Templates;
  22. import javax.xml.transform.TransformerException;
  23. import javax.xml.transform.URIResolver;
  24. import javax.xml.transform.sax.TemplatesHandler;
  25. import com.sun.org.apache.xalan.internal.xsltc.compiler.CompilerException;
  26. import com.sun.org.apache.xalan.internal.xsltc.compiler.Parser;
  27. import com.sun.org.apache.xalan.internal.xsltc.compiler.SourceLoader;
  28. import com.sun.org.apache.xalan.internal.xsltc.compiler.Stylesheet;
  29. import com.sun.org.apache.xalan.internal.xsltc.compiler.SyntaxTreeNode;
  30. import com.sun.org.apache.xalan.internal.xsltc.compiler.XSLTC;
  31. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
  32. import org.xml.sax.ContentHandler;
  33. import org.xml.sax.InputSource;
  34. import org.xml.sax.Locator;
  35. import org.xml.sax.SAXException;
  36. import org.xml.sax.Attributes;
  37. import java.util.Vector;
  38. /**
  39. * Implementation of a JAXP1.1 TemplatesHandler
  40. * @author Morten Jorgensen
  41. * @author Santiago Pericas-Geertsen
  42. */
  43. public class TemplatesHandlerImpl
  44. implements ContentHandler, TemplatesHandler, SourceLoader
  45. {
  46. /**
  47. * System ID for this stylesheet.
  48. */
  49. private String _systemId;
  50. /**
  51. * Number of spaces to add for output indentation.
  52. */
  53. private int _indentNumber;
  54. /**
  55. * This URIResolver is passed to all Transformers.
  56. */
  57. private URIResolver _uriResolver = null;
  58. /**
  59. * A reference to the transformer factory that this templates
  60. * object belongs to.
  61. */
  62. private TransformerFactoryImpl _tfactory = null;
  63. /**
  64. * A reference to XSLTC's parser object.
  65. */
  66. private Parser _parser = null;
  67. /**
  68. * The created Templates object.
  69. */
  70. private TemplatesImpl _templates = null;
  71. /**
  72. * Default constructor
  73. */
  74. protected TemplatesHandlerImpl(int indentNumber,
  75. TransformerFactoryImpl tfactory)
  76. {
  77. _indentNumber = indentNumber;
  78. _tfactory = tfactory;
  79. // Instantiate XSLTC and get reference to parser object
  80. _parser = new XSLTC().getParser();
  81. }
  82. /**
  83. * Implements javax.xml.transform.sax.TemplatesHandler.getSystemId()
  84. * Get the base ID (URI or system ID) from where relative URLs will be
  85. * resolved.
  86. * @return The systemID that was set with setSystemId(String id)
  87. */
  88. public String getSystemId() {
  89. return _systemId;
  90. }
  91. /**
  92. * Implements javax.xml.transform.sax.TemplatesHandler.setSystemId()
  93. * Get the base ID (URI or system ID) from where relative URLs will be
  94. * resolved.
  95. * @param id Base URI for this stylesheet
  96. */
  97. public void setSystemId(String id) {
  98. _systemId = id;
  99. }
  100. /**
  101. * Store URIResolver needed for Transformers.
  102. */
  103. public void setURIResolver(URIResolver resolver) {
  104. _uriResolver = resolver;
  105. }
  106. /**
  107. * Implements javax.xml.transform.sax.TemplatesHandler.getTemplates()
  108. * When a TemplatesHandler object is used as a ContentHandler or
  109. * DocumentHandler for the parsing of transformation instructions, it
  110. * creates a Templates object, which the caller can get once the SAX
  111. * events have been completed.
  112. * @return The Templates object that was created during the SAX event
  113. * process, or null if no Templates object has been created.
  114. */
  115. public Templates getTemplates() {
  116. return _templates;
  117. }
  118. /**
  119. * This method implements XSLTC's SourceLoader interface. It is used to
  120. * glue a TrAX URIResolver to the XSLTC compiler's Input and Import classes.
  121. *
  122. * @param href The URI of the document to load
  123. * @param context The URI of the currently loaded document
  124. * @param xsltc The compiler that resuests the document
  125. * @return An InputSource with the loaded document
  126. */
  127. public InputSource loadSource(String href, String context, XSLTC xsltc) {
  128. try {
  129. // A _uriResolver must be set if this method is called
  130. final Source source = _uriResolver.resolve(href, context);
  131. if (source != null) {
  132. return Util.getInputSource(xsltc, source);
  133. }
  134. }
  135. catch (TransformerException e) {
  136. // Falls through
  137. }
  138. return null;
  139. }
  140. // -- ContentHandler --------------------------------------------------
  141. /**
  142. * Re-initialize parser and forward SAX2 event.
  143. */
  144. public void startDocument() {
  145. XSLTC xsltc = _parser.getXSLTC();
  146. xsltc.init(); // calls _parser.init()
  147. xsltc.setOutputType(XSLTC.BYTEARRAY_OUTPUT);
  148. _parser.startDocument();
  149. }
  150. /**
  151. * Just forward SAX2 event to parser object.
  152. */
  153. public void endDocument() throws SAXException {
  154. _parser.endDocument();
  155. // create the templates
  156. try {
  157. XSLTC xsltc = _parser.getXSLTC();
  158. // Set the translet class name if not already set
  159. String transletName = null;
  160. if (_systemId != null) {
  161. transletName = Util.baseName(_systemId);
  162. }
  163. else {
  164. transletName = (String)_tfactory.getAttribute("translet-name");
  165. }
  166. xsltc.setClassName(transletName);
  167. // Get java-legal class name from XSLTC module
  168. transletName = xsltc.getClassName();
  169. Stylesheet stylesheet = null;
  170. SyntaxTreeNode root = _parser.getDocumentRoot();
  171. // Compile the translet - this is where the work is done!
  172. if (!_parser.errorsFound() && root != null) {
  173. // Create a Stylesheet element from the root node
  174. stylesheet = _parser.makeStylesheet(root);
  175. stylesheet.setSystemId(_systemId);
  176. stylesheet.setParentStylesheet(null);
  177. // Set a document loader (for xsl:include/import) if defined
  178. if (_uriResolver != null) {
  179. stylesheet.setSourceLoader(this);
  180. }
  181. _parser.setCurrentStylesheet(stylesheet);
  182. // Set it as top-level in the XSLTC object
  183. xsltc.setStylesheet(stylesheet);
  184. // Create AST under the Stylesheet element
  185. _parser.createAST(stylesheet);
  186. }
  187. // Generate the bytecodes and output the translet class(es)
  188. if (!_parser.errorsFound() && stylesheet != null) {
  189. stylesheet.setMultiDocument(xsltc.isMultiDocument());
  190. stylesheet.setHasIdCall(xsltc.hasIdCall());
  191. // Class synchronization is needed for BCEL
  192. synchronized (xsltc.getClass()) {
  193. stylesheet.translate();
  194. }
  195. }
  196. if (!_parser.errorsFound()) {
  197. // Check that the transformation went well before returning
  198. final byte[][] bytecodes = xsltc.getBytecodes();
  199. if (bytecodes != null) {
  200. _templates =
  201. new TemplatesImpl(xsltc.getBytecodes(), transletName,
  202. _parser.getOutputProperties(), _indentNumber, _tfactory);
  203. // Set URIResolver on templates object
  204. if (_uriResolver != null) {
  205. _templates.setURIResolver(_uriResolver);
  206. }
  207. }
  208. }
  209. else {
  210. StringBuffer errorMessage = new StringBuffer();
  211. Vector errors = _parser.getErrors();
  212. final int count = errors.size();
  213. for (int i = 0; i < count; i++) {
  214. if (errorMessage.length() > 0)
  215. errorMessage.append('\n');
  216. errorMessage.append(errors.elementAt(i).toString());
  217. }
  218. throw new SAXException(ErrorMsg.JAXP_COMPILE_ERR, new TransformerException(errorMessage.toString()));
  219. }
  220. }
  221. catch (CompilerException e) {
  222. throw new SAXException(ErrorMsg.JAXP_COMPILE_ERR, e);
  223. }
  224. }
  225. /**
  226. * Just forward SAX2 event to parser object.
  227. */
  228. public void startPrefixMapping(String prefix, String uri) {
  229. _parser.startPrefixMapping(prefix, uri);
  230. }
  231. /**
  232. * Just forward SAX2 event to parser object.
  233. */
  234. public void endPrefixMapping(String prefix) {
  235. _parser.endPrefixMapping(prefix);
  236. }
  237. /**
  238. * Just forward SAX2 event to parser object.
  239. */
  240. public void startElement(String uri, String localname, String qname,
  241. Attributes attributes) throws SAXException
  242. {
  243. _parser.startElement(uri, localname, qname, attributes);
  244. }
  245. /**
  246. * Just forward SAX2 event to parser object.
  247. */
  248. public void endElement(String uri, String localname, String qname) {
  249. _parser.endElement(uri, localname, qname);
  250. }
  251. /**
  252. * Just forward SAX2 event to parser object.
  253. */
  254. public void characters(char[] ch, int start, int length) {
  255. _parser.characters(ch, start, length);
  256. }
  257. /**
  258. * Just forward SAX2 event to parser object.
  259. */
  260. public void processingInstruction(String name, String value) {
  261. _parser.processingInstruction(name, value);
  262. }
  263. /**
  264. * Just forward SAX2 event to parser object.
  265. */
  266. public void ignorableWhitespace(char[] ch, int start, int length) {
  267. _parser.ignorableWhitespace(ch, start, length);
  268. }
  269. /**
  270. * Just forward SAX2 event to parser object.
  271. */
  272. public void skippedEntity(String name) {
  273. _parser.skippedEntity(name);
  274. }
  275. /**
  276. * Set internal system Id and forward SAX2 event to parser object.
  277. */
  278. public void setDocumentLocator(Locator locator) {
  279. setSystemId(locator.getSystemId());
  280. _parser.setDocumentLocator(locator);
  281. }
  282. }