1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 1999 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Xalan" and "Apache Software Foundation" must
  28. * not be used to endorse or promote products derived from this
  29. * software without prior written permission. For written
  30. * permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * nor may "Apache" appear in their name, without prior written
  34. * permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation and was
  52. * originally based on software copyright (c) 1999, Lotus
  53. * Development Corporation., http://www.lotus.com. For more
  54. * information on the Apache Software Foundation, please see
  55. * <http://www.apache.org/>.
  56. */
  57. package org.apache.xalan.processor;
  58. import org.xml.sax.InputSource;
  59. import org.xml.sax.helpers.XMLReaderFactory;
  60. import org.xml.sax.XMLReader;
  61. import javax.xml.transform.TransformerException;
  62. import org.xml.sax.SAXNotRecognizedException;
  63. import org.xml.sax.SAXNotSupportedException;
  64. import org.xml.sax.XMLFilter;
  65. import org.w3c.dom.Node;
  66. import org.apache.xml.utils.TreeWalker;
  67. import org.apache.xml.utils.SystemIDResolver;
  68. import org.apache.xml.utils.DefaultErrorHandler;
  69. import org.apache.xalan.transformer.TransformerImpl;
  70. import org.apache.xalan.transformer.TransformerIdentityImpl;
  71. import org.apache.xalan.transformer.TrAXFilter;
  72. import org.apache.xalan.res.XSLMessages;
  73. import org.apache.xalan.res.XSLTErrorResources;
  74. import javax.xml.transform.Transformer;
  75. import javax.xml.transform.TransformerFactory;
  76. import javax.xml.transform.TransformerConfigurationException;
  77. import javax.xml.transform.Source;
  78. import javax.xml.transform.URIResolver;
  79. import javax.xml.transform.Templates;
  80. import javax.xml.transform.sax.TemplatesHandler;
  81. import javax.xml.transform.sax.TransformerHandler;
  82. import javax.xml.transform.sax.SAXTransformerFactory;
  83. import javax.xml.transform.sax.SAXSource;
  84. import javax.xml.transform.sax.SAXResult;
  85. import javax.xml.transform.dom.DOMSource;
  86. import javax.xml.transform.dom.DOMResult;
  87. import javax.xml.transform.stream.StreamSource;
  88. import javax.xml.transform.stream.StreamResult;
  89. import javax.xml.transform.ErrorListener;
  90. import java.io.IOException;
  91. import java.io.InputStream;
  92. import java.io.BufferedInputStream;
  93. import java.io.StringWriter;
  94. import java.io.PrintWriter;
  95. import java.io.StringReader;
  96. import java.util.Properties;
  97. import java.util.Enumeration;
  98. import org.apache.xalan.transformer.XalanProperties;
  99. /**
  100. * The TransformerFactoryImpl, which implements the TRaX TransformerFactory
  101. * interface, processes XSLT stylesheets into a Templates object
  102. * (a StylesheetRoot).
  103. */
  104. public class TransformerFactoryImpl extends SAXTransformerFactory
  105. {
  106. /**
  107. * The path/filename of the property file: XSLTInfo.properties
  108. * Maintenance note: see also org.apache.xpath.functions.FuncSystemProperty.XSLT_PROPERTIES
  109. */
  110. public static String XSLT_PROPERTIES =
  111. "org/apache/xalan/res/XSLTInfo.properties";
  112. /**
  113. * Constructor TransformerFactoryImpl
  114. *
  115. */
  116. public TransformerFactoryImpl()
  117. {
  118. }
  119. /** a zero length Class array used in loadPropertyFileToSystem() */
  120. private static final Class[] NO_CLASSES = new Class[0];
  121. /** a zero length Object array used in loadPropertyFileToSystem() */
  122. private static final Object[] NO_OBJS = new Object[0];
  123. /** Static string to be used for incremental feature */
  124. public static final String FEATURE_INCREMENTAL = "http://xml.apache.org/xalan/features/incremental";
  125. /** Static string to be used for optimize feature */
  126. public static final String FEATURE_OPTIMIZE = "http://xml.apache.org/xalan/features/optimize";
  127. /** Static string to be used for source_location feature */
  128. public static final String FEATURE_SOURCE_LOCATION = XalanProperties.SOURCE_LOCATION;
  129. /**
  130. * Retrieve a propery bundle from XSLT_PROPERTIES and load it
  131. * int the System properties.
  132. */
  133. static
  134. {
  135. try
  136. {
  137. InputStream is = null;
  138. try
  139. {
  140. Properties props = new Properties();
  141. try {
  142. java.lang.reflect.Method getCCL = Thread.class.getMethod("getContextClassLoader", NO_CLASSES);
  143. if (getCCL != null) {
  144. ClassLoader contextClassLoader = (ClassLoader) getCCL.invoke(Thread.currentThread(), NO_OBJS);
  145. is = contextClassLoader.getResourceAsStream(XSLT_PROPERTIES); // file should be already fully specified
  146. }
  147. }
  148. catch (Exception e) {}
  149. if (is == null) {
  150. // NOTE! For the below getResourceAsStream in Sun JDK 1.1.8M
  151. // we apparently must add the leading slash character - I
  152. // don't know why, but if it's not there, we throw an NPE from the below loading
  153. is = TransformerFactoryImpl.class.getResourceAsStream("/" + XSLT_PROPERTIES); // file should be already fully specified
  154. }
  155. // get a buffered version
  156. BufferedInputStream bis = new BufferedInputStream(is);
  157. props.load(bis); // and load up the property bag from this
  158. bis.close(); // close out after reading
  159. // OK, now we only want to set system properties that
  160. // are not already set.
  161. Properties systemProps = System.getProperties();
  162. Enumeration propEnum = props.propertyNames();
  163. while (propEnum.hasMoreElements())
  164. {
  165. String prop = (String) propEnum.nextElement();
  166. if (!systemProps.containsKey(prop))
  167. systemProps.put(prop, props.getProperty(prop));
  168. }
  169. System.setProperties(systemProps);
  170. }
  171. catch (Exception ex){}
  172. }
  173. catch (SecurityException se)
  174. {
  175. // In this case the caller is required to have
  176. // the needed attributes already defined.
  177. }
  178. }
  179. public javax.xml.transform.Templates processFromNode(Node node)
  180. throws TransformerConfigurationException
  181. {
  182. try
  183. {
  184. TemplatesHandler builder = newTemplatesHandler();
  185. TreeWalker walker = new TreeWalker(builder, new org.apache.xpath.DOM2Helper(), builder.getSystemId());
  186. walker.traverse(node);
  187. return builder.getTemplates();
  188. }
  189. catch (org.xml.sax.SAXException se)
  190. {
  191. if (m_errorListener != null)
  192. {
  193. try
  194. {
  195. m_errorListener.fatalError(new TransformerException(se));
  196. }
  197. catch (TransformerException ex)
  198. {
  199. throw new TransformerConfigurationException(ex);
  200. }
  201. return null;
  202. }
  203. else
  204. // Should remove this later... but right now diagnostics from
  205. // TransformerConfigurationException are not good.
  206. // se.printStackTrace();
  207. throw new TransformerConfigurationException(XSLMessages.createMessage(XSLTErrorResources.ER_PROCESSFROMNODE_FAILED, null), se); //"processFromNode failed",
  208. //se);
  209. }
  210. catch (TransformerConfigurationException tce)
  211. {
  212. // Assume it's already been reported to the error listener.
  213. throw tce;
  214. }
  215. /* catch (TransformerException tce)
  216. {
  217. // Assume it's already been reported to the error listener.
  218. throw new TransformerConfigurationException(tce.getMessage(), tce);
  219. }*/
  220. catch (Exception e)
  221. {
  222. if (m_errorListener != null)
  223. {
  224. try
  225. {
  226. m_errorListener.fatalError(new TransformerException(e));
  227. }
  228. catch (TransformerException ex)
  229. {
  230. throw new TransformerConfigurationException(ex);
  231. }
  232. return null;
  233. }
  234. else
  235. // Should remove this later... but right now diagnostics from
  236. // TransformerConfigurationException are not good.
  237. // se.printStackTrace();
  238. throw new TransformerConfigurationException(XSLMessages.createMessage(XSLTErrorResources.ER_PROCESSFROMNODE_FAILED, null), e); //"processFromNode failed",
  239. //e);
  240. }
  241. }
  242. /**
  243. * The systemID that was specified in
  244. * processFromNode(Node node, String systemID).
  245. */
  246. private String m_DOMsystemID = null;
  247. /**
  248. * The systemID that was specified in
  249. * processFromNode(Node node, String systemID).
  250. *
  251. * @return The systemID, or null.
  252. */
  253. String getDOMsystemID()
  254. {
  255. return m_DOMsystemID;
  256. }
  257. /**
  258. * Process the stylesheet from a DOM tree, if the
  259. * processor supports the "http://xml.org/trax/features/dom/input"
  260. * feature.
  261. *
  262. * @param node A DOM tree which must contain
  263. * valid transform instructions that this processor understands.
  264. * @param systemID The systemID from where xsl:includes and xsl:imports
  265. * should be resolved from.
  266. *
  267. * @return A Templates object capable of being used for transformation purposes.
  268. *
  269. * @throws TransformerConfigurationException
  270. */
  271. javax.xml.transform.Templates processFromNode(Node node, String systemID)
  272. throws TransformerConfigurationException
  273. {
  274. m_DOMsystemID = systemID;
  275. return processFromNode(node);
  276. }
  277. /**
  278. * Get InputSource specification(s) that are associated with the
  279. * given document specified in the source param,
  280. * via the xml-stylesheet processing instruction
  281. * (see http://www.w3.org/TR/xml-stylesheet/), and that matches
  282. * the given criteria. Note that it is possible to return several stylesheets
  283. * that match the criteria, in which case they are applied as if they were
  284. * a list of imports or cascades.
  285. *
  286. * <p>Note that DOM2 has it's own mechanism for discovering stylesheets.
  287. * Therefore, there isn't a DOM version of this method.</p>
  288. *
  289. *
  290. * @param source The XML source that is to be searched.
  291. * @param media The media attribute to be matched. May be null, in which
  292. * case the prefered templates will be used (i.e. alternate = no).
  293. * @param title The value of the title attribute to match. May be null.
  294. * @param charset The value of the charset attribute to match. May be null.
  295. *
  296. * @return A Source object capable of being used to create a Templates object.
  297. *
  298. * @throws TransformerConfigurationException
  299. */
  300. public Source getAssociatedStylesheet(
  301. Source source, String media, String title, String charset)
  302. throws TransformerConfigurationException
  303. {
  304. String baseID;
  305. InputSource isource = null;
  306. Node node = null;
  307. XMLReader reader = null;
  308. if (source instanceof DOMSource)
  309. {
  310. DOMSource dsource = (DOMSource) source;
  311. node = dsource.getNode();
  312. baseID = dsource.getSystemId();
  313. }
  314. else
  315. {
  316. isource = SAXSource.sourceToInputSource(source);
  317. baseID = isource.getSystemId();
  318. }
  319. // What I try to do here is parse until the first startElement
  320. // is found, then throw a special exception in order to terminate
  321. // the parse.
  322. StylesheetPIHandler handler = new StylesheetPIHandler(baseID, media,
  323. title, charset);
  324. // Use URIResolver. Patch from Dmitri Ilyin
  325. if (m_uriResolver != null)
  326. {
  327. handler.setURIResolver(m_uriResolver);
  328. }
  329. try
  330. {
  331. if (null != node)
  332. {
  333. TreeWalker walker = new TreeWalker(handler, new org.apache.xpath.DOM2Helper(), baseID);
  334. walker.traverse(node);
  335. }
  336. else
  337. {
  338. // Use JAXP1.1 ( if possible )
  339. try
  340. {
  341. javax.xml.parsers.SAXParserFactory factory =
  342. javax.xml.parsers.SAXParserFactory.newInstance();
  343. factory.setNamespaceAware(true);
  344. javax.xml.parsers.SAXParser jaxpParser = factory.newSAXParser();
  345. reader = jaxpParser.getXMLReader();
  346. }
  347. catch (javax.xml.parsers.ParserConfigurationException ex)
  348. {
  349. throw new org.xml.sax.SAXException(ex);
  350. }
  351. catch (javax.xml.parsers.FactoryConfigurationError ex1)
  352. {
  353. throw new org.xml.sax.SAXException(ex1.toString());
  354. }
  355. catch (NoSuchMethodError ex2){}
  356. catch (AbstractMethodError ame){}
  357. if (null == reader)
  358. {
  359. reader = XMLReaderFactory.createXMLReader();
  360. }
  361. // Need to set options!
  362. reader.setContentHandler(handler);
  363. reader.parse(isource);
  364. }
  365. }
  366. catch (StopParseException spe)
  367. {
  368. // OK, good.
  369. }
  370. catch (org.xml.sax.SAXException se)
  371. {
  372. throw new TransformerConfigurationException(
  373. "getAssociatedStylesheets failed", se);
  374. }
  375. catch (IOException ioe)
  376. {
  377. throw new TransformerConfigurationException(
  378. "getAssociatedStylesheets failed", ioe);
  379. }
  380. return handler.getAssociatedStylesheet();
  381. }
  382. /**
  383. * Create a new Transformer object that performs a copy
  384. * of the source to the result.
  385. *
  386. * @param source An object that holds a URI, input stream, etc.
  387. *
  388. * @return A Transformer object that may be used to perform a transformation
  389. * in a single thread, never null.
  390. *
  391. * @throws TransformerConfigurationException May throw this during
  392. * the parse when it is constructing the
  393. * Templates object and fails.
  394. */
  395. public TemplatesHandler newTemplatesHandler()
  396. throws TransformerConfigurationException
  397. {
  398. return new StylesheetHandler(this);
  399. }
  400. /**
  401. * Look up the value of a feature.
  402. *
  403. * <p>The feature name is any fully-qualified URI. It is
  404. * possible for an TransformerFactory to recognize a feature name but
  405. * to be unable to return its value; this is especially true
  406. * in the case of an adapter for a SAX1 Parser, which has
  407. * no way of knowing whether the underlying parser is
  408. * validating, for example.</p>
  409. *
  410. * @param name The feature name, which is a fully-qualified URI.
  411. * @return The current state of the feature (true or false).
  412. */
  413. public boolean getFeature(String name)
  414. {
  415. // Try first with identity comparison, which
  416. // will be faster.
  417. if ((DOMResult.FEATURE == name) || (DOMSource.FEATURE == name)
  418. || (SAXResult.FEATURE == name) || (SAXSource.FEATURE == name)
  419. || (StreamResult.FEATURE == name)
  420. || (StreamSource.FEATURE == name)
  421. || (SAXTransformerFactory.FEATURE == name)
  422. || (SAXTransformerFactory.FEATURE_XMLFILTER == name))
  423. return true;
  424. else if ((DOMResult.FEATURE.equals(name))
  425. || (DOMSource.FEATURE.equals(name))
  426. || (SAXResult.FEATURE.equals(name))
  427. || (SAXSource.FEATURE.equals(name))
  428. || (StreamResult.FEATURE.equals(name))
  429. || (StreamSource.FEATURE.equals(name))
  430. || (SAXTransformerFactory.FEATURE.equals(name))
  431. || (SAXTransformerFactory.FEATURE_XMLFILTER.equals(name)))
  432. return true;
  433. else
  434. return false;
  435. }
  436. public static boolean m_optimize = true;
  437. /** Flag set by FEATURE_SOURCE_LOCATION.
  438. * This feature specifies whether the transformation phase should
  439. * keep track of line and column numbers for the input source
  440. * document. Note that this works only when that
  441. * information is available from the source -- in other words, if you
  442. * pass in a DOM, there's little we can do for you.
  443. *
  444. * The default is false. Setting it true may significantly
  445. * increase storage cost per node.
  446. *
  447. * %REVIEW% SAX2DTM is explicitly reaching up to retrieve this global field.
  448. * We should instead have an architected pathway for passing hints of this
  449. * sort down from TransformerFactory to Transformer to DTMManager to DTM.
  450. * */
  451. public static boolean m_source_location = false;
  452. /**
  453. * Allows the user to set specific attributes on the underlying
  454. * implementation.
  455. *
  456. * @param name The name of the attribute.
  457. * @param value The value of the attribute; Boolean or String="true"|"false"
  458. *
  459. * @throws IllegalArgumentException thrown if the underlying
  460. * implementation doesn't recognize the attribute.
  461. */
  462. public void setAttribute(String name, Object value)
  463. throws IllegalArgumentException
  464. {
  465. if (name.equals(FEATURE_INCREMENTAL))
  466. {
  467. if(value instanceof Boolean)
  468. {
  469. // Accept a Boolean object..
  470. org.apache.xml.dtm.DTMManager.setIncremental(((Boolean)value).booleanValue());
  471. }
  472. else if(value instanceof String)
  473. {
  474. // .. or a String object
  475. org.apache.xml.dtm.DTMManager.setIncremental((new Boolean((String)value)).booleanValue());
  476. }
  477. else
  478. {
  479. // Give a more meaningful error message
  480. throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_BAD_VALUE, new Object[]{name, value})); //name + " bad value " + value);
  481. }
  482. }
  483. else if (name.equals(FEATURE_OPTIMIZE))
  484. {
  485. if(value instanceof Boolean)
  486. {
  487. // Accept a Boolean object..
  488. m_optimize = ((Boolean)value).booleanValue();
  489. }
  490. else if(value instanceof String)
  491. {
  492. // .. or a String object
  493. m_optimize = (new Boolean((String)value)).booleanValue();
  494. }
  495. else
  496. {
  497. // Give a more meaningful error message
  498. throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_BAD_VALUE, new Object[]{name, value})); //name + " bad value " + value);
  499. }
  500. }
  501. // Custom Xalan feature: annotate DTM with SAX source locator fields.
  502. // This gets used during SAX2DTM instantiation.
  503. //
  504. // %REVIEW% Should the name of this field really be in XalanProperties?
  505. // %REVIEW% I hate that it's a global static, but didn't want to change APIs yet.
  506. else if(name.equals(FEATURE_SOURCE_LOCATION))
  507. {
  508. if(value instanceof Boolean)
  509. {
  510. // Accept a Boolean object..
  511. m_source_location = ((Boolean)value).booleanValue();
  512. }
  513. else if(value instanceof String)
  514. {
  515. // .. or a String object
  516. m_source_location = (new Boolean((String)value)).booleanValue();
  517. }
  518. else
  519. {
  520. // Give a more meaningful error message
  521. throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_BAD_VALUE, new Object[]{name, value})); //name + " bad value " + value);
  522. }
  523. }
  524. else
  525. {
  526. throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_NOT_SUPPORTED, new Object[]{name})); //name + "not supported");
  527. }
  528. }
  529. /**
  530. * Allows the user to retrieve specific attributes on the underlying
  531. * implementation.
  532. *
  533. * @param name The name of the attribute.
  534. * @return value The value of the attribute.
  535. *
  536. * @throws IllegalArgumentException thrown if the underlying
  537. * implementation doesn't recognize the attribute.
  538. */
  539. public Object getAttribute(String name) throws IllegalArgumentException
  540. {
  541. if (name.equals(FEATURE_INCREMENTAL))
  542. {
  543. return new Boolean(org.apache.xml.dtm.DTMManager.getIncremental());
  544. }
  545. else if (name.equals(FEATURE_OPTIMIZE))
  546. {
  547. return new Boolean(m_optimize);
  548. }
  549. else if (name.equals(FEATURE_SOURCE_LOCATION))
  550. {
  551. return new Boolean(m_source_location);
  552. }
  553. else
  554. throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_ATTRIB_VALUE_NOT_RECOGNIZED, new Object[]{name})); //name + " attribute not recognized");
  555. }
  556. /**
  557. * Create an XMLFilter that uses the given source as the
  558. * transformation instructions.
  559. *
  560. * @param src The source of the transformation instructions.
  561. *
  562. * @return An XMLFilter object, or null if this feature is not supported.
  563. *
  564. * @throws TransformerConfigurationException
  565. */
  566. public XMLFilter newXMLFilter(Source src)
  567. throws TransformerConfigurationException
  568. {
  569. Templates templates = newTemplates(src);
  570. if( templates==null ) return null;
  571. return newXMLFilter(templates);
  572. }
  573. /**
  574. * Create an XMLFilter that uses the given source as the
  575. * transformation instructions.
  576. *
  577. * @param src The source of the transformation instructions.
  578. *
  579. * @param templates non-null reference to Templates object.
  580. *
  581. * @return An XMLFilter object, or null if this feature is not supported.
  582. *
  583. * @throws TransformerConfigurationException
  584. */
  585. public XMLFilter newXMLFilter(Templates templates)
  586. throws TransformerConfigurationException
  587. {
  588. try {
  589. return new TrAXFilter(templates);
  590. } catch( TransformerConfigurationException ex ) {
  591. if( m_errorListener != null) {
  592. try {
  593. m_errorListener.fatalError( ex );
  594. return null;
  595. } catch( TransformerException ex1 ) {
  596. new TransformerConfigurationException(ex1);
  597. }
  598. }
  599. throw ex;
  600. }
  601. }
  602. /**
  603. * Get a TransformerHandler object that can process SAX
  604. * ContentHandler events into a Result, based on the transformation
  605. * instructions specified by the argument.
  606. *
  607. * @param src The source of the transformation instructions.
  608. *
  609. * @return TransformerHandler ready to transform SAX events.
  610. *
  611. * @throws TransformerConfigurationException
  612. */
  613. public TransformerHandler newTransformerHandler(Source src)
  614. throws TransformerConfigurationException
  615. {
  616. Templates templates = newTemplates(src);
  617. if( templates==null ) return null;
  618. return newTransformerHandler(templates);
  619. }
  620. /**
  621. * Get a TransformerHandler object that can process SAX
  622. * ContentHandler events into a Result, based on the Templates argument.
  623. *
  624. * @param templates The source of the transformation instructions.
  625. *
  626. * @return TransformerHandler ready to transform SAX events.
  627. * @throws TransformerConfigurationException
  628. */
  629. public TransformerHandler newTransformerHandler(Templates templates)
  630. throws TransformerConfigurationException
  631. {
  632. try {
  633. TransformerImpl transformer =
  634. (TransformerImpl) templates.newTransformer();
  635. transformer.setURIResolver(m_uriResolver);
  636. TransformerHandler th =
  637. (TransformerHandler) transformer.getInputContentHandler(true);
  638. return th;
  639. } catch( TransformerConfigurationException ex ) {
  640. if( m_errorListener != null ) {
  641. try {
  642. m_errorListener.fatalError( ex );
  643. return null;
  644. } catch (TransformerException ex1 ) {
  645. ex=new TransformerConfigurationException(ex1);
  646. }
  647. }
  648. throw ex;
  649. }
  650. }
  651. // /** The identity transform string, for support of newTransformerHandler()
  652. // * and newTransformer(). */
  653. // private static final String identityTransform =
  654. // "<xsl:stylesheet " + "xmlns:xsl='http://www.w3.org/1999/XSL/Transform' "
  655. // + "version='1.0'>" + "<xsl:template match='/|node()'>"
  656. // + "<xsl:copy-of select='.'/>" + "</xsl:template>" + "</xsl:stylesheet>";
  657. //
  658. // /** The identity transform Templates, built from identityTransform,
  659. // * for support of newTransformerHandler() and newTransformer(). */
  660. // private static Templates m_identityTemplate = null;
  661. /**
  662. * Get a TransformerHandler object that can process SAX
  663. * ContentHandler events into a Result.
  664. *
  665. * @param src The source of the transformation instructions.
  666. *
  667. * @return TransformerHandler ready to transform SAX events.
  668. *
  669. * @throws TransformerConfigurationException
  670. */
  671. public TransformerHandler newTransformerHandler()
  672. throws TransformerConfigurationException
  673. {
  674. // if (null == m_identityTemplate)
  675. // {
  676. // synchronized (identityTransform)
  677. // {
  678. // if (null == m_identityTemplate)
  679. // {
  680. // StringReader reader = new StringReader(identityTransform);
  681. //
  682. // m_identityTemplate = newTemplates(new StreamSource(reader));
  683. // }
  684. // }
  685. // }
  686. //
  687. // return newTransformerHandler(m_identityTemplate);
  688. return new TransformerIdentityImpl();
  689. }
  690. /**
  691. * Process the source into a Transformer object. Care must
  692. * be given to know that this object can not be used concurrently
  693. * in multiple threads.
  694. *
  695. * @param source An object that holds a URL, input stream, etc.
  696. *
  697. * @return A Transformer object capable of
  698. * being used for transformation purposes in a single thread.
  699. *
  700. * @throws TransformerConfigurationException May throw this during the parse when it
  701. * is constructing the Templates object and fails.
  702. */
  703. public Transformer newTransformer(Source source)
  704. throws TransformerConfigurationException
  705. {
  706. try {
  707. Templates tmpl=newTemplates( source );
  708. /* this can happen if an ErrorListener is present and it doesn't
  709. throw any exception in fatalError.
  710. The spec says: "a Transformer must use this interface
  711. instead of throwing an exception" - the newTemplates() does
  712. that, and returns null.
  713. */
  714. if( tmpl==null ) return null;
  715. Transformer transformer = tmpl.newTransformer();
  716. transformer.setURIResolver(m_uriResolver);
  717. return transformer;
  718. } catch( TransformerConfigurationException ex ) {
  719. if( m_errorListener != null ) {
  720. try {
  721. m_errorListener.fatalError( ex );
  722. return null;
  723. } catch( TransformerException ex1 ) {
  724. ex=new TransformerConfigurationException( ex1 );
  725. }
  726. }
  727. throw ex;
  728. }
  729. }
  730. /**
  731. * Create a new Transformer object that performs a copy
  732. * of the source to the result.
  733. *
  734. * @param source An object that holds a URL, input stream, etc.
  735. *
  736. * @return A Transformer object capable of
  737. * being used for transformation purposes in a single thread.
  738. *
  739. * @throws TransformerConfigurationException May throw this during
  740. * the parse when it is constructing the
  741. * Templates object and it fails.
  742. */
  743. public Transformer newTransformer() throws TransformerConfigurationException
  744. {
  745. // if (null == m_identityTemplate)
  746. // {
  747. // synchronized (identityTransform)
  748. // {
  749. // if (null == m_identityTemplate)
  750. // {
  751. // StringReader reader = new StringReader(identityTransform);
  752. //
  753. // m_identityTemplate = newTemplates(new StreamSource(reader));
  754. // }
  755. // }
  756. // }
  757. //
  758. // return m_identityTemplate.newTransformer();
  759. return new TransformerIdentityImpl();
  760. }
  761. /**
  762. * Process the source into a Templates object, which is likely
  763. * a compiled representation of the source. This Templates object
  764. * may then be used concurrently across multiple threads. Creating
  765. * a Templates object allows the TransformerFactory to do detailed
  766. * performance optimization of transformation instructions, without
  767. * penalizing runtime transformation.
  768. *
  769. * @param source An object that holds a URL, input stream, etc.
  770. * @return A Templates object capable of being used for transformation purposes.
  771. *
  772. * @throws TransformerConfigurationException May throw this during the parse when it
  773. * is constructing the Templates object and fails.
  774. */
  775. public Templates newTemplates(Source source)
  776. throws TransformerConfigurationException
  777. {
  778. TemplatesHandler builder = newTemplatesHandler();
  779. String baseID = source.getSystemId();
  780. if (null == baseID)
  781. {
  782. try
  783. {
  784. String currentDir = System.getProperty("user.dir");
  785. if (currentDir.startsWith(java.io.File.separator))
  786. baseID = "file://" + currentDir + java.io.File.separatorChar
  787. + source.getClass().getName();
  788. else
  789. baseID = "file:///" + currentDir + java.io.File.separatorChar
  790. + source.getClass().getName();
  791. }
  792. catch (SecurityException se)
  793. {
  794. // For untrusted applet case, user.dir is outside the sandbox
  795. // and not accessible: just leave baseID as null (-sb & -sc)
  796. }
  797. }
  798. else
  799. {
  800. try
  801. {
  802. baseID = SystemIDResolver.getAbsoluteURI(baseID);
  803. }
  804. catch (TransformerException te)
  805. {
  806. throw new TransformerConfigurationException(te);
  807. }
  808. }
  809. builder.setSystemId(baseID);
  810. if (source instanceof DOMSource)
  811. {
  812. DOMSource dsource = (DOMSource) source;
  813. Node node = dsource.getNode();
  814. if (null != node)
  815. return processFromNode(node, baseID);
  816. else
  817. {
  818. String messageStr = XSLMessages.createMessage(
  819. XSLTErrorResources.ER_ILLEGAL_DOMSOURCE_INPUT, null);
  820. throw new IllegalArgumentException(messageStr);
  821. }
  822. }
  823. try
  824. {
  825. InputSource isource = SAXSource.sourceToInputSource(source);
  826. XMLReader reader = null;
  827. if (source instanceof SAXSource)
  828. reader = ((SAXSource) source).getXMLReader();
  829. boolean isUserReader = (reader != null);
  830. if (null == reader)
  831. {
  832. // Use JAXP1.1 ( if possible )
  833. try
  834. {
  835. javax.xml.parsers.SAXParserFactory factory =
  836. javax.xml.parsers.SAXParserFactory.newInstance();
  837. factory.setNamespaceAware(true);
  838. javax.xml.parsers.SAXParser jaxpParser = factory.newSAXParser();
  839. reader = jaxpParser.getXMLReader();
  840. }
  841. catch (javax.xml.parsers.ParserConfigurationException ex)
  842. {
  843. throw new org.xml.sax.SAXException(ex);
  844. }
  845. catch (javax.xml.parsers.FactoryConfigurationError ex1)
  846. {
  847. throw new org.xml.sax.SAXException(ex1.toString());
  848. }
  849. catch (NoSuchMethodError ex2){}
  850. catch (AbstractMethodError ame){}
  851. }
  852. if (null == reader)
  853. reader = XMLReaderFactory.createXMLReader();
  854. // If you set the namespaces to true, we'll end up getting double
  855. // xmlns attributes. Needs to be fixed. -sb
  856. // reader.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
  857. try
  858. {
  859. if(!isUserReader)
  860. reader.setFeature("http://apache.org/xml/features/validation/dynamic",
  861. true);
  862. }
  863. catch (org.xml.sax.SAXException ex)
  864. {
  865. // feature not recognized
  866. }
  867. reader.setContentHandler(builder);
  868. reader.parse(isource);
  869. }
  870. catch (org.xml.sax.SAXException se)
  871. {
  872. if (m_errorListener != null)
  873. {
  874. try
  875. {
  876. m_errorListener.fatalError(new TransformerException(se));
  877. }
  878. catch (TransformerException ex1)
  879. {
  880. throw new TransformerConfigurationException(ex1);
  881. }
  882. }
  883. else
  884. throw new TransformerConfigurationException(se.getMessage(), se);
  885. }
  886. catch (Exception e)
  887. {
  888. if (m_errorListener != null)
  889. {
  890. try
  891. {
  892. m_errorListener.fatalError(new TransformerException(e));
  893. return null;
  894. }
  895. catch (TransformerException ex1)
  896. {
  897. throw new TransformerConfigurationException(ex1);
  898. }
  899. }
  900. else
  901. throw new TransformerConfigurationException(e.getMessage(), e);
  902. }
  903. return builder.getTemplates();
  904. }
  905. /**
  906. * The object that implements the URIResolver interface,
  907. * or null.
  908. */
  909. URIResolver m_uriResolver;
  910. /**
  911. * Set an object that will be used to resolve URIs used in
  912. * xsl:import, etc. This will be used as the default for the
  913. * transformation.
  914. * @param resolver An object that implements the URIResolver interface,
  915. * or null.
  916. */
  917. public void setURIResolver(URIResolver resolver)
  918. {
  919. m_uriResolver = resolver;
  920. }
  921. /**
  922. * Get the object that will be used to resolve URIs used in
  923. * xsl:import, etc. This will be used as the default for the
  924. * transformation.
  925. *
  926. * @return The URIResolver that was set with setURIResolver.
  927. */
  928. public URIResolver getURIResolver()
  929. {
  930. return m_uriResolver;
  931. }
  932. /** The error listener. */
  933. private ErrorListener m_errorListener = new DefaultErrorHandler();
  934. /**
  935. * Get the error listener in effect for the TransformerFactory.
  936. *
  937. * @return A non-null reference to an error listener.
  938. */
  939. public ErrorListener getErrorListener()
  940. {
  941. return m_errorListener;
  942. }
  943. /**
  944. * Set an error listener for the TransformerFactory.
  945. *
  946. * @param listener Must be a non-null reference to an ErrorListener.
  947. *
  948. * @throws IllegalArgumentException if the listener argument is null.
  949. */
  950. public void setErrorListener(ErrorListener listener)
  951. throws IllegalArgumentException
  952. {
  953. if (null == listener)
  954. throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_ERRORLISTENER, null));
  955. // "ErrorListener");
  956. m_errorListener = listener;
  957. }
  958. }