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.transformer;
  58. import java.util.Properties;
  59. import java.util.Hashtable;
  60. import java.io.IOException;
  61. // TRaX Imports
  62. import javax.xml.transform.*;
  63. import javax.xml.transform.dom.*;
  64. import javax.xml.transform.sax.*;
  65. import javax.xml.transform.stream.*;
  66. import javax.xml.parsers.*;
  67. import org.xml.sax.*;
  68. import org.xml.sax.helpers.*;
  69. import org.xml.sax.ext.*;
  70. import org.apache.xalan.serialize.*;
  71. import org.apache.xml.utils.DOMBuilder;
  72. import org.apache.xml.utils.TreeWalker;
  73. import org.apache.xalan.templates.OutputProperties;
  74. import org.apache.xalan.serialize.Method;
  75. import org.apache.xalan.res.XSLTErrorResources;
  76. import org.apache.xalan.res.XSLMessages;
  77. import org.w3c.dom.*;
  78. /**
  79. * This class implements an identity transformer for
  80. * {@link javax.xml.transform.sax.SAXTransformerFactory#newTransformerHandler()
  81. * and {@link javax.xml.transform.TransformerFactory#newTransformer()}. It
  82. * simply feeds SAX events directly to a serializer ContentHandler, if the
  83. * result is a stream. If the result is a DOM, it will send the events to
  84. * {@link org.apache.xml.utils.DOMBuilder}. If the result is another
  85. * content handler, it will simply pass the events on.
  86. */
  87. public class TransformerIdentityImpl extends Transformer
  88. implements TransformerHandler, DeclHandler
  89. {
  90. /**
  91. * Constructor TransformerIdentityImpl creates an identity transform.
  92. *
  93. */
  94. public TransformerIdentityImpl()
  95. {
  96. m_outputFormat = new OutputProperties(Method.XML);
  97. }
  98. /**
  99. * Enables the user of the TransformerHandler to set the
  100. * to set the Result for the transformation.
  101. *
  102. * @param result A Result instance, should not be null.
  103. *
  104. * @throws IllegalArgumentException if result is invalid for some reason.
  105. */
  106. public void setResult(Result result) throws IllegalArgumentException
  107. {
  108. if(null == result)
  109. throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_RESULT_NULL, null)); //"Result should not be null");
  110. m_result = result;
  111. }
  112. /**
  113. * Set the base ID (URI or system ID) from where relative
  114. * URLs will be resolved.
  115. * @param systemID Base URI for the source tree.
  116. */
  117. public void setSystemId(String systemID)
  118. {
  119. m_systemID = systemID;
  120. }
  121. /**
  122. * Get the base ID (URI or system ID) from where relative
  123. * URLs will be resolved.
  124. * @return The systemID that was set with {@link #setSystemId}.
  125. */
  126. public String getSystemId()
  127. {
  128. return m_systemID;
  129. }
  130. /**
  131. * Get the Transformer associated with this handler, which
  132. * is needed in order to set parameters and output properties.
  133. *
  134. * @return non-null reference to the transformer.
  135. */
  136. public Transformer getTransformer()
  137. {
  138. return this;
  139. }
  140. /**
  141. * Create a result ContentHandler from a Result object, based
  142. * on the current OutputProperties.
  143. *
  144. * @param outputTarget Where the transform result should go,
  145. * should not be null.
  146. *
  147. * @return A valid ContentHandler that will create the
  148. * result tree when it is fed SAX events.
  149. *
  150. * @throws TransformerException
  151. */
  152. private void createResultContentHandler(Result outputTarget)
  153. throws TransformerException
  154. {
  155. if (outputTarget instanceof SAXResult)
  156. {
  157. SAXResult saxResult = (SAXResult) outputTarget;
  158. m_resultContentHandler = saxResult.getHandler();
  159. m_resultLexicalHandler = saxResult.getLexicalHandler();
  160. if (m_resultContentHandler instanceof Serializer)
  161. {
  162. // Dubious but needed, I think.
  163. m_serializer = (Serializer) m_resultContentHandler;
  164. }
  165. }
  166. else if (outputTarget instanceof DOMResult)
  167. {
  168. DOMResult domResult = (DOMResult) outputTarget;
  169. Node outputNode = domResult.getNode();
  170. Document doc;
  171. short type;
  172. if (null != outputNode)
  173. {
  174. type = outputNode.getNodeType();
  175. doc = (Node.DOCUMENT_NODE == type)
  176. ? (Document) outputNode : outputNode.getOwnerDocument();
  177. }
  178. else
  179. {
  180. try
  181. {
  182. DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
  183. dbf.setNamespaceAware(true);
  184. DocumentBuilder db = dbf.newDocumentBuilder();
  185. doc = db.newDocument();
  186. }
  187. catch (ParserConfigurationException pce)
  188. {
  189. throw new TransformerException(pce);
  190. }
  191. outputNode = doc;
  192. type = outputNode.getNodeType();
  193. ((DOMResult) outputTarget).setNode(outputNode);
  194. }
  195. m_resultContentHandler =
  196. (Node.DOCUMENT_FRAGMENT_NODE == type)
  197. ? new DOMBuilder(doc, (DocumentFragment) outputNode)
  198. : new DOMBuilder(doc, outputNode);
  199. m_resultLexicalHandler = (LexicalHandler) m_resultContentHandler;
  200. }
  201. else if (outputTarget instanceof StreamResult)
  202. {
  203. StreamResult sresult = (StreamResult) outputTarget;
  204. String method = m_outputFormat.getProperty(OutputKeys.METHOD);
  205. try
  206. {
  207. Serializer serializer =
  208. SerializerFactory.getSerializer(m_outputFormat.getProperties());
  209. m_serializer = serializer;
  210. if (null != sresult.getWriter())
  211. serializer.setWriter(sresult.getWriter());
  212. else if (null != sresult.getOutputStream())
  213. serializer.setOutputStream(sresult.getOutputStream());
  214. else if (null != sresult.getSystemId())
  215. {
  216. String fileURL = sresult.getSystemId();
  217. if (fileURL.startsWith("file:///"))
  218. {
  219. if (fileURL.substring(8).indexOf(":") >0)
  220. fileURL = fileURL.substring(8);
  221. else
  222. fileURL = fileURL.substring(7);
  223. }
  224. m_outputStream = new java.io.FileOutputStream(fileURL);
  225. serializer.setOutputStream(m_outputStream);
  226. }
  227. else
  228. throw new TransformerException(XSLMessages.createMessage(XSLTErrorResources.ER_NO_OUTPUT_SPECIFIED, null)); //"No output specified!");
  229. m_resultContentHandler = serializer.asContentHandler();
  230. }
  231. catch (IOException ioe)
  232. {
  233. throw new TransformerException(ioe);
  234. }
  235. }
  236. else
  237. {
  238. throw new TransformerException(XSLMessages.createMessage(XSLTErrorResources.ER_CANNOT_TRANSFORM_TO_RESULT_TYPE, new Object[]{outputTarget.getClass().getName()})); //"Can't transform to a Result of type "
  239. // + outputTarget.getClass().getName()
  240. // + "!");
  241. }
  242. if (m_resultContentHandler instanceof DTDHandler)
  243. m_resultDTDHandler = (DTDHandler) m_resultContentHandler;
  244. if (m_resultContentHandler instanceof DeclHandler)
  245. m_resultDeclHandler = (DeclHandler) m_resultContentHandler;
  246. if (m_resultContentHandler instanceof LexicalHandler)
  247. m_resultLexicalHandler = (LexicalHandler) m_resultContentHandler;
  248. }
  249. /**
  250. * Process the source tree to the output result.
  251. * @param source The input for the source tree.
  252. *
  253. * @param outputTarget The output target.
  254. *
  255. * @throws TransformerException If an unrecoverable error occurs
  256. * during the course of the transformation.
  257. */
  258. public void transform(Source source, Result outputTarget)
  259. throws TransformerException
  260. {
  261. createResultContentHandler(outputTarget);
  262. try
  263. {
  264. if (source instanceof DOMSource)
  265. {
  266. DOMSource dsource = (DOMSource) source;
  267. m_systemID = dsource.getSystemId();
  268. Node dNode = dsource.getNode();
  269. if (null != dNode)
  270. {
  271. try
  272. {
  273. if(dNode.getNodeType() != Node.DOCUMENT_NODE)
  274. this.startDocument();
  275. try
  276. {
  277. if(dNode.getNodeType() == Node.ATTRIBUTE_NODE)
  278. {
  279. String data = dNode.getNodeValue();
  280. char[] chars = data.toCharArray();
  281. characters(chars, 0, chars.length);
  282. }
  283. else
  284. {
  285. TreeWalker walker = new TreeWalker(this, new org.apache.xpath.DOM2Helper(), m_systemID);
  286. walker.traverse(dNode);
  287. }
  288. }
  289. finally
  290. {
  291. if(dNode.getNodeType() != Node.DOCUMENT_NODE)
  292. this.endDocument();
  293. }
  294. }
  295. catch (SAXException se)
  296. {
  297. throw new TransformerException(se);
  298. }
  299. return;
  300. }
  301. else
  302. {
  303. String messageStr = XSLMessages.createMessage(
  304. XSLTErrorResources.ER_ILLEGAL_DOMSOURCE_INPUT, null);
  305. throw new IllegalArgumentException(messageStr);
  306. }
  307. }
  308. InputSource xmlSource = SAXSource.sourceToInputSource(source);
  309. if (null == xmlSource)
  310. {
  311. throw new TransformerException(XSLMessages.createMessage(XSLTErrorResources.ER_CANNOT_TRANSFORM_SOURCE_TYPE, new Object[]{source.getClass().getName()})); //"Can't transform a Source of type "
  312. //+ source.getClass().getName() + "!");
  313. }
  314. if (null != xmlSource.getSystemId())
  315. m_systemID = xmlSource.getSystemId();
  316. try
  317. {
  318. XMLReader reader = null;
  319. if (source instanceof SAXSource)
  320. reader = ((SAXSource) source).getXMLReader();
  321. boolean isUserReader = (reader != null);
  322. if (null == reader)
  323. {
  324. // Use JAXP1.1 ( if possible )
  325. try
  326. {
  327. javax.xml.parsers.SAXParserFactory factory =
  328. javax.xml.parsers.SAXParserFactory.newInstance();
  329. factory.setNamespaceAware(true);
  330. javax.xml.parsers.SAXParser jaxpParser = factory.newSAXParser();
  331. reader = jaxpParser.getXMLReader();
  332. }
  333. catch (javax.xml.parsers.ParserConfigurationException ex)
  334. {
  335. throw new org.xml.sax.SAXException(ex);
  336. }
  337. catch (javax.xml.parsers.FactoryConfigurationError ex1)
  338. {
  339. throw new org.xml.sax.SAXException(ex1.toString());
  340. }
  341. catch (NoSuchMethodError ex2){}
  342. catch (AbstractMethodError ame){}
  343. }
  344. if (null == reader)
  345. {
  346. reader = XMLReaderFactory.createXMLReader();
  347. }
  348. try
  349. {
  350. reader.setFeature("http://xml.org/sax/features/namespace-prefixes",
  351. true);
  352. // Commented out as per discussion with Thomas2.Maesing@bgs-ag.de
  353. // about bug 2124.
  354. // if(!isUserReader)
  355. // reader.setFeature("http://apache.org/xml/features/validation/dynamic",
  356. // true);
  357. }
  358. catch (org.xml.sax.SAXException se)
  359. {
  360. // We don't care.
  361. }
  362. // Get the input content handler, which will handle the
  363. // parse events and create the source tree.
  364. ContentHandler inputHandler = this;
  365. reader.setContentHandler(inputHandler);
  366. if (inputHandler instanceof org.xml.sax.DTDHandler)
  367. reader.setDTDHandler((org.xml.sax.DTDHandler) inputHandler);
  368. try
  369. {
  370. if (inputHandler instanceof org.xml.sax.ext.LexicalHandler)
  371. reader.setProperty("http://xml.org/sax/properties/lexical-handler",
  372. inputHandler);
  373. if (inputHandler instanceof org.xml.sax.ext.DeclHandler)
  374. reader.setProperty(
  375. "http://xml.org/sax/properties/declaration-handler",
  376. inputHandler);
  377. }
  378. catch (org.xml.sax.SAXException se){}
  379. try
  380. {
  381. if (inputHandler instanceof org.xml.sax.ext.LexicalHandler)
  382. reader.setProperty("http://xml.org/sax/handlers/LexicalHandler",
  383. inputHandler);
  384. if (inputHandler instanceof org.xml.sax.ext.DeclHandler)
  385. reader.setProperty("http://xml.org/sax/handlers/DeclHandler",
  386. inputHandler);
  387. }
  388. catch (org.xml.sax.SAXNotRecognizedException snre){}
  389. reader.parse(xmlSource);
  390. }
  391. catch (org.apache.xml.utils.WrappedRuntimeException wre)
  392. {
  393. Throwable throwable = wre.getException();
  394. while (throwable
  395. instanceof org.apache.xml.utils.WrappedRuntimeException)
  396. {
  397. throwable =
  398. ((org.apache.xml.utils.WrappedRuntimeException) throwable).getException();
  399. }
  400. throw new TransformerException(wre.getException());
  401. }
  402. catch (org.xml.sax.SAXException se)
  403. {
  404. throw new TransformerException(se);
  405. }
  406. catch (IOException ioe)
  407. {
  408. throw new TransformerException(ioe);
  409. }
  410. }
  411. finally
  412. {
  413. if(null != m_outputStream)
  414. {
  415. try
  416. {
  417. m_outputStream.close();
  418. }
  419. catch(IOException ioe){}
  420. m_outputStream = null;
  421. }
  422. }
  423. }
  424. /**
  425. * Add a parameter for the transformation.
  426. *
  427. * <p>Pass a qualified name as a two-part string, the namespace URI
  428. * enclosed in curly braces ({}), followed by the local name. If the
  429. * name has a null URL, the String only contain the local name. An
  430. * application can safely check for a non-null URI by testing to see if the first
  431. * character of the name is a '{' character.</p>
  432. * <p>For example, if a URI and local name were obtained from an element
  433. * defined with <xyz:foo xmlns:xyz="http://xyz.foo.com/yada/baz.html"/>,
  434. * then the qualified name would be "{http://xyz.foo.com/yada/baz.html}foo". Note that
  435. * no prefix is used.</p>
  436. *
  437. * @param name The name of the parameter, which may begin with a namespace URI
  438. * in curly braces ({}).
  439. * @param value The value object. This can be any valid Java object. It is
  440. * up to the processor to provide the proper object coersion or to simply
  441. * pass the object on for use in an extension.
  442. */
  443. public void setParameter(String name, Object value)
  444. {
  445. if (null == m_params)
  446. {
  447. m_params = new Hashtable();
  448. }
  449. m_params.put(name, value);
  450. }
  451. /**
  452. * Get a parameter that was explicitly set with setParameter
  453. * or setParameters.
  454. *
  455. * <p>This method does not return a default parameter value, which
  456. * cannot be determined until the node context is evaluated during
  457. * the transformation process.
  458. *
  459. *
  460. * @param name Name of the parameter.
  461. * @return A parameter that has been set with setParameter.
  462. */
  463. public Object getParameter(String name)
  464. {
  465. if (null == m_params)
  466. return null;
  467. return m_params.get(name);
  468. }
  469. /**
  470. * Clear all parameters set with setParameter.
  471. */
  472. public void clearParameters()
  473. {
  474. if (null == m_params)
  475. return;
  476. m_params.clear();
  477. }
  478. /**
  479. * Set an object that will be used to resolve URIs used in
  480. * document().
  481. *
  482. * <p>If the resolver argument is null, the URIResolver value will
  483. * be cleared, and the default behavior will be used.</p>
  484. *
  485. * @param resolver An object that implements the URIResolver interface,
  486. * or null.
  487. */
  488. public void setURIResolver(URIResolver resolver)
  489. {
  490. m_URIResolver = resolver;
  491. }
  492. /**
  493. * Get an object that will be used to resolve URIs used in
  494. * document(), etc.
  495. *
  496. * @return An object that implements the URIResolver interface,
  497. * or null.
  498. */
  499. public URIResolver getURIResolver()
  500. {
  501. return m_URIResolver;
  502. }
  503. /**
  504. * Set the output properties for the transformation. These
  505. * properties will override properties set in the Templates
  506. * with xsl:output.
  507. *
  508. * <p>If argument to this function is null, any properties
  509. * previously set are removed, and the value will revert to the value
  510. * defined in the templates object.</p>
  511. *
  512. * <p>Pass a qualified property key name as a two-part string, the namespace URI
  513. * enclosed in curly braces ({}), followed by the local name. If the
  514. * name has a null URL, the String only contain the local name. An
  515. * application can safely check for a non-null URI by testing to see if the first
  516. * character of the name is a '{' character.</p>
  517. * <p>For example, if a URI and local name were obtained from an element
  518. * defined with <xyz:foo xmlns:xyz="http://xyz.foo.com/yada/baz.html"/>,
  519. * then the qualified name would be "{http://xyz.foo.com/yada/baz.html}foo". Note that
  520. * no prefix is used.</p>
  521. *
  522. * @param oformat A set of output properties that will be
  523. * used to override any of the same properties in affect
  524. * for the transformation.
  525. *
  526. * @see javax.xml.transform.OutputKeys
  527. * @see java.util.Properties
  528. *
  529. * @throws IllegalArgumentException if any of the argument keys are not
  530. * recognized and are not namespace qualified.
  531. */
  532. public void setOutputProperties(Properties oformat)
  533. throws IllegalArgumentException
  534. {
  535. if (null != oformat)
  536. {
  537. // See if an *explicit* method was set.
  538. String method = (String) oformat.get(OutputKeys.METHOD);
  539. if (null != method)
  540. m_outputFormat = new OutputProperties(method);
  541. else
  542. m_outputFormat = new OutputProperties();
  543. }
  544. if (null != oformat)
  545. {
  546. m_outputFormat.copyFrom(oformat);
  547. }
  548. }
  549. /**
  550. * Get a copy of the output properties for the transformation.
  551. *
  552. * <p>The properties returned should contain properties set by the user,
  553. * and properties set by the stylesheet, and these properties
  554. * are "defaulted" by default properties specified by <a href="http://www.w3.org/TR/xslt#output">section 16 of the
  555. * XSL Transformations (XSLT) W3C Recommendation</a>. The properties that
  556. * were specifically set by the user or the stylesheet should be in the base
  557. * Properties list, while the XSLT default properties that were not
  558. * specifically set should be the default Properties list. Thus,
  559. * getOutputProperties().getProperty(String key) will obtain any
  560. * property in that was set by {@link #setOutputProperty},
  561. * {@link #setOutputProperties}, in the stylesheet, <em>or</em> the default
  562. * properties, while
  563. * getOutputProperties().get(String key) will only retrieve properties
  564. * that were explicitly set by {@link #setOutputProperty},
  565. * {@link #setOutputProperties}, or in the stylesheet.</p>
  566. *
  567. * <p>Note that mutation of the Properties object returned will not
  568. * effect the properties that the transformation contains.</p>
  569. *
  570. * <p>If any of the argument keys are not recognized and are not
  571. * namespace qualified, the property will be ignored. In other words the
  572. * behaviour is not orthogonal with setOutputProperties.</p>
  573. *
  574. * @return A copy of the set of output properties in effect
  575. * for the next transformation.
  576. *
  577. * @see javax.xml.transform.OutputKeys
  578. * @see java.util.Properties
  579. */
  580. public Properties getOutputProperties()
  581. {
  582. return (Properties) m_outputFormat.getProperties().clone();
  583. }
  584. /**
  585. * Set an output property that will be in effect for the
  586. * transformation.
  587. *
  588. * <p>Pass a qualified property name as a two-part string, the namespace URI
  589. * enclosed in curly braces ({}), followed by the local name. If the
  590. * name has a null URL, the String only contain the local name. An
  591. * application can safely check for a non-null URI by testing to see if the first
  592. * character of the name is a '{' character.</p>
  593. * <p>For example, if a URI and local name were obtained from an element
  594. * defined with <xyz:foo xmlns:xyz="http://xyz.foo.com/yada/baz.html"/>,
  595. * then the qualified name would be "{http://xyz.foo.com/yada/baz.html}foo". Note that
  596. * no prefix is used.</p>
  597. *
  598. * <p>The Properties object that was passed to {@link #setOutputProperties} won't
  599. * be effected by calling this method.</p>
  600. *
  601. * @param name A non-null String that specifies an output
  602. * property name, which may be namespace qualified.
  603. * @param value The non-null string value of the output property.
  604. *
  605. * @throws IllegalArgumentException If the property is not supported, and is
  606. * not qualified with a namespace.
  607. *
  608. * @see javax.xml.transform.OutputKeys
  609. */
  610. public void setOutputProperty(String name, String value)
  611. throws IllegalArgumentException
  612. {
  613. if (!m_outputFormat.isLegalPropertyKey(name))
  614. throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_OUTPUT_PROPERTY_NOT_RECOGNIZED, new Object[]{name})); //"output property not recognized: "
  615. //+ name);
  616. m_outputFormat.setProperty(name, value);
  617. }
  618. /**
  619. * Get an output property that is in effect for the
  620. * transformation. The property specified may be a property
  621. * that was set with setOutputProperty, or it may be a
  622. * property specified in the stylesheet.
  623. *
  624. * @param name A non-null String that specifies an output
  625. * property name, which may be namespace qualified.
  626. *
  627. * @return The string value of the output property, or null
  628. * if no property was found.
  629. *
  630. * @throws IllegalArgumentException If the property is not supported.
  631. *
  632. * @see javax.xml.transform.OutputKeys
  633. */
  634. public String getOutputProperty(String name) throws IllegalArgumentException
  635. {
  636. String value = null;
  637. OutputProperties props = m_outputFormat;
  638. value = props.getProperty(name);
  639. if (null == value)
  640. {
  641. if (!props.isLegalPropertyKey(name))
  642. throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_OUTPUT_PROPERTY_NOT_RECOGNIZED, new Object[]{name})); //"output property not recognized: "
  643. // + name);
  644. }
  645. return value;
  646. }
  647. /**
  648. * Set the error event listener in effect for the transformation.
  649. *
  650. * @param listener The new error listener.
  651. * @throws IllegalArgumentException if listener is null.
  652. */
  653. public void setErrorListener(ErrorListener listener)
  654. throws IllegalArgumentException
  655. {
  656. if (listener == null)
  657. throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_NULL_ERROR_HANDLER, null));
  658. else
  659. m_errorListener = listener;
  660. }
  661. /**
  662. * Get the error event handler in effect for the transformation.
  663. *
  664. * @return The current error handler, which should never be null.
  665. */
  666. public ErrorListener getErrorListener()
  667. {
  668. return m_errorListener;
  669. }
  670. ////////////////////////////////////////////////////////////////////
  671. // Default implementation of DTDHandler interface.
  672. ////////////////////////////////////////////////////////////////////
  673. /**
  674. * Receive notification of a notation declaration.
  675. *
  676. * <p>By default, do nothing. Application writers may override this
  677. * method in a subclass if they wish to keep track of the notations
  678. * declared in a document.</p>
  679. *
  680. * @param name The notation name.
  681. * @param publicId The notation public identifier, or null if not
  682. * available.
  683. * @param systemId The notation system identifier.
  684. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  685. * wrapping another exception.
  686. * @see org.xml.sax.DTDHandler#notationDecl
  687. *
  688. * @throws SAXException
  689. */
  690. public void notationDecl(String name, String publicId, String systemId)
  691. throws SAXException
  692. {
  693. if (null != m_resultDTDHandler)
  694. m_resultDTDHandler.notationDecl(name, publicId, systemId);
  695. }
  696. /**
  697. * Receive notification of an unparsed entity declaration.
  698. *
  699. * <p>By default, do nothing. Application writers may override this
  700. * method in a subclass to keep track of the unparsed entities
  701. * declared in a document.</p>
  702. *
  703. * @param name The entity name.
  704. * @param publicId The entity public identifier, or null if not
  705. * available.
  706. * @param systemId The entity system identifier.
  707. * @param notationName The name of the associated notation.
  708. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  709. * wrapping another exception.
  710. * @see org.xml.sax.DTDHandler#unparsedEntityDecl
  711. *
  712. * @throws SAXException
  713. */
  714. public void unparsedEntityDecl(
  715. String name, String publicId, String systemId, String notationName)
  716. throws SAXException
  717. {
  718. if (null != m_resultDTDHandler)
  719. m_resultDTDHandler.unparsedEntityDecl(name, publicId, systemId,
  720. notationName);
  721. }
  722. ////////////////////////////////////////////////////////////////////
  723. // Default implementation of ContentHandler interface.
  724. ////////////////////////////////////////////////////////////////////
  725. /**
  726. * Receive a Locator object for document events.
  727. *
  728. * <p>By default, do nothing. Application writers may override this
  729. * method in a subclass if they wish to store the locator for use
  730. * with other document events.</p>
  731. *
  732. * @param locator A locator for all SAX document events.
  733. * @see org.xml.sax.ContentHandler#setDocumentLocator
  734. * @see org.xml.sax.Locator
  735. */
  736. public void setDocumentLocator(Locator locator)
  737. {
  738. try
  739. {
  740. if (null == m_resultContentHandler)
  741. createResultContentHandler(m_result);
  742. }
  743. catch (TransformerException te)
  744. {
  745. throw new org.apache.xml.utils.WrappedRuntimeException(te);
  746. }
  747. m_resultContentHandler.setDocumentLocator(locator);
  748. }
  749. /**
  750. * Receive notification of the beginning of the document.
  751. *
  752. * <p>By default, do nothing. Application writers may override this
  753. * method in a subclass to take specific actions at the beginning
  754. * of a document (such as allocating the root node of a tree or
  755. * creating an output file).</p>
  756. *
  757. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  758. * wrapping another exception.
  759. * @see org.xml.sax.ContentHandler#startDocument
  760. *
  761. * @throws SAXException
  762. */
  763. public void startDocument() throws SAXException
  764. {
  765. try
  766. {
  767. if (null == m_resultContentHandler)
  768. createResultContentHandler(m_result);
  769. }
  770. catch (TransformerException te)
  771. {
  772. throw new SAXException(te.getMessage(), te);
  773. }
  774. // Reset for multiple transforms with this transformer.
  775. m_flushedStartDoc = false;
  776. m_foundFirstElement = false;
  777. }
  778. boolean m_flushedStartDoc = false;
  779. protected final void flushStartDoc()
  780. throws SAXException
  781. {
  782. if(!m_flushedStartDoc)
  783. {
  784. m_resultContentHandler.startDocument();
  785. m_flushedStartDoc = true;
  786. }
  787. }
  788. /**
  789. * Receive notification of the end of the document.
  790. *
  791. * <p>By default, do nothing. Application writers may override this
  792. * method in a subclass to take specific actions at the end
  793. * of a document (such as finalising a tree or closing an output
  794. * file).</p>
  795. *
  796. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  797. * wrapping another exception.
  798. * @see org.xml.sax.ContentHandler#endDocument
  799. *
  800. * @throws SAXException
  801. */
  802. public void endDocument() throws SAXException
  803. {
  804. flushStartDoc();
  805. m_resultContentHandler.endDocument();
  806. }
  807. /**
  808. * Receive notification of the start of a Namespace mapping.
  809. *
  810. * <p>By default, do nothing. Application writers may override this
  811. * method in a subclass to take specific actions at the start of
  812. * each Namespace prefix scope (such as storing the prefix mapping).</p>
  813. *
  814. * @param prefix The Namespace prefix being declared.
  815. * @param uri The Namespace URI mapped to the prefix.
  816. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  817. * wrapping another exception.
  818. * @see org.xml.sax.ContentHandler#startPrefixMapping
  819. *
  820. * @throws SAXException
  821. */
  822. public void startPrefixMapping(String prefix, String uri)
  823. throws SAXException
  824. {
  825. flushStartDoc();
  826. m_resultContentHandler.startPrefixMapping(prefix, uri);
  827. }
  828. /**
  829. * Receive notification of the end of a Namespace mapping.
  830. *
  831. * <p>By default, do nothing. Application writers may override this
  832. * method in a subclass to take specific actions at the end of
  833. * each prefix mapping.</p>
  834. *
  835. * @param prefix The Namespace prefix being declared.
  836. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  837. * wrapping another exception.
  838. * @see org.xml.sax.ContentHandler#endPrefixMapping
  839. *
  840. * @throws SAXException
  841. */
  842. public void endPrefixMapping(String prefix) throws SAXException
  843. {
  844. flushStartDoc();
  845. m_resultContentHandler.endPrefixMapping(prefix);
  846. }
  847. /**
  848. * Receive notification of the start of an element.
  849. *
  850. * <p>By default, do nothing. Application writers may override this
  851. * method in a subclass to take specific actions at the start of
  852. * each element (such as allocating a new tree node or writing
  853. * output to a file).</p>
  854. *
  855. * @param uri The Namespace URI, or the empty string if the
  856. * element has no Namespace URI or if Namespace
  857. * processing is not being performed.
  858. * @param localName The local name (without prefix), or the
  859. * empty string if Namespace processing is not being
  860. * performed.
  861. * @param qName The qualified name (with prefix), or the
  862. * empty string if qualified names are not available.
  863. * @param attributes The specified or defaulted attributes.
  864. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  865. * wrapping another exception.
  866. * @see org.xml.sax.ContentHandler#startElement
  867. *
  868. * @throws SAXException
  869. */
  870. public void startElement(
  871. String uri, String localName, String qName, Attributes attributes)
  872. throws SAXException
  873. {
  874. if (!m_foundFirstElement && null != m_serializer)
  875. {
  876. m_foundFirstElement = true;
  877. Serializer newSerializer;
  878. try
  879. {
  880. newSerializer = SerializerSwitcher.switchSerializerIfHTML(uri,
  881. localName, m_outputFormat.getProperties(), m_serializer);
  882. }
  883. catch (TransformerException te)
  884. {
  885. throw new SAXException(te);
  886. }
  887. if (newSerializer != m_serializer)
  888. {
  889. try
  890. {
  891. m_resultContentHandler = newSerializer.asContentHandler();
  892. }
  893. catch (IOException ioe) // why?
  894. {
  895. throw new SAXException(ioe);
  896. }
  897. if (m_resultContentHandler instanceof DTDHandler)
  898. m_resultDTDHandler = (DTDHandler) m_resultContentHandler;
  899. if (m_resultContentHandler instanceof LexicalHandler)
  900. m_resultLexicalHandler = (LexicalHandler) m_resultContentHandler;
  901. m_serializer = newSerializer;
  902. }
  903. }
  904. flushStartDoc();
  905. m_resultContentHandler.startElement(uri, localName, qName, attributes);
  906. }
  907. /**
  908. * Receive notification of the end of an element.
  909. *
  910. * <p>By default, do nothing. Application writers may override this
  911. * method in a subclass to take specific actions at the end of
  912. * each element (such as finalising a tree node or writing
  913. * output to a file).</p>
  914. *
  915. * @param uri The Namespace URI, or the empty string if the
  916. * element has no Namespace URI or if Namespace
  917. * processing is not being performed.
  918. * @param localName The local name (without prefix), or the
  919. * empty string if Namespace processing is not being
  920. * performed.
  921. * @param qName The qualified name (with prefix), or the
  922. * empty string if qualified names are not available.
  923. * @param attributes The specified or defaulted attributes.
  924. *
  925. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  926. * wrapping another exception.
  927. * @see org.xml.sax.ContentHandler#endElement
  928. *
  929. * @throws SAXException
  930. */
  931. public void endElement(String uri, String localName, String qName)
  932. throws SAXException
  933. {
  934. m_resultContentHandler.endElement(uri, localName, qName);
  935. }
  936. /**
  937. * Receive notification of character data inside an element.
  938. *
  939. * <p>By default, do nothing. Application writers may override this
  940. * method to take specific actions for each chunk of character data
  941. * (such as adding the data to a node or buffer, or printing it to
  942. * a file).</p>
  943. *
  944. * @param ch The characters.
  945. * @param start The start position in the character array.
  946. * @param length The number of characters to use from the
  947. * character array.
  948. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  949. * wrapping another exception.
  950. * @see org.xml.sax.ContentHandler#characters
  951. *
  952. * @throws SAXException
  953. */
  954. public void characters(char ch[], int start, int length) throws SAXException
  955. {
  956. flushStartDoc();
  957. m_resultContentHandler.characters(ch, start, length);
  958. }
  959. /**
  960. * Receive notification of ignorable whitespace in element content.
  961. *
  962. * <p>By default, do nothing. Application writers may override this
  963. * method to take specific actions for each chunk of ignorable
  964. * whitespace (such as adding data to a node or buffer, or printing
  965. * it to a file).</p>
  966. *
  967. * @param ch The whitespace characters.
  968. * @param start The start position in the character array.
  969. * @param length The number of characters to use from the
  970. * character array.
  971. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  972. * wrapping another exception.
  973. * @see org.xml.sax.ContentHandler#ignorableWhitespace
  974. *
  975. * @throws SAXException
  976. */
  977. public void ignorableWhitespace(char ch[], int start, int length)
  978. throws SAXException
  979. {
  980. m_resultContentHandler.ignorableWhitespace(ch, start, length);
  981. }
  982. /**
  983. * Receive notification of a processing instruction.
  984. *
  985. * <p>By default, do nothing. Application writers may override this
  986. * method in a subclass to take specific actions for each
  987. * processing instruction, such as setting status variables or
  988. * invoking other methods.</p>
  989. *
  990. * @param target The processing instruction target.
  991. * @param data The processing instruction data, or null if
  992. * none is supplied.
  993. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  994. * wrapping another exception.
  995. * @see org.xml.sax.ContentHandler#processingInstruction
  996. *
  997. * @throws SAXException
  998. */
  999. public void processingInstruction(String target, String data)
  1000. throws SAXException
  1001. {
  1002. flushStartDoc();
  1003. m_resultContentHandler.processingInstruction(target, data);
  1004. }
  1005. /**
  1006. * Receive notification of a skipped entity.
  1007. *
  1008. * <p>By default, do nothing. Application writers may override this
  1009. * method in a subclass to take specific actions for each
  1010. * processing instruction, such as setting status variables or
  1011. * invoking other methods.</p>
  1012. *
  1013. * @param name The name of the skipped entity.
  1014. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  1015. * wrapping another exception.
  1016. * @see org.xml.sax.ContentHandler#processingInstruction
  1017. *
  1018. * @throws SAXException
  1019. */
  1020. public void skippedEntity(String name) throws SAXException
  1021. {
  1022. flushStartDoc();
  1023. m_resultContentHandler.skippedEntity(name);
  1024. }
  1025. /**
  1026. * Report the start of DTD declarations, if any.
  1027. *
  1028. * <p>Any declarations are assumed to be in the internal subset
  1029. * unless otherwise indicated by a {@link #startEntity startEntity}
  1030. * event.</p>
  1031. *
  1032. * <p>Note that the start/endDTD events will appear within
  1033. * the start/endDocument events from ContentHandler and
  1034. * before the first startElement event.</p>
  1035. *
  1036. * @param name The document type name.
  1037. * @param publicId The declared public identifier for the
  1038. * external DTD subset, or null if none was declared.
  1039. * @param systemId The declared system identifier for the
  1040. * external DTD subset, or null if none was declared.
  1041. * @throws SAXException The application may raise an
  1042. * exception.
  1043. * @see #endDTD
  1044. * @see #startEntity
  1045. */
  1046. public void startDTD(String name, String publicId, String systemId)
  1047. throws SAXException
  1048. {
  1049. flushStartDoc();
  1050. if (null != m_resultLexicalHandler)
  1051. m_resultLexicalHandler.startDTD(name, publicId, systemId);
  1052. }
  1053. /**
  1054. * Report the end of DTD declarations.
  1055. *
  1056. * @throws SAXException The application may raise an exception.
  1057. * @see #startDTD
  1058. */
  1059. public void endDTD() throws SAXException
  1060. {
  1061. if (null != m_resultLexicalHandler)
  1062. m_resultLexicalHandler.endDTD();
  1063. }
  1064. /**
  1065. * Report the beginning of an entity in content.
  1066. *
  1067. * <p><strong>NOTE:</entity> entity references in attribute
  1068. * values -- and the start and end of the document entity --
  1069. * are never reported.</p>
  1070. *
  1071. * <p>The start and end of the external DTD subset are reported
  1072. * using the pseudo-name "[dtd]". All other events must be
  1073. * properly nested within start/end entity events.</p>
  1074. *
  1075. * <p>Note that skipped entities will be reported through the
  1076. * {@link org.xml.sax.ContentHandler#skippedEntity skippedEntity}
  1077. * event, which is part of the ContentHandler interface.</p>
  1078. *
  1079. * @param name The name of the entity. If it is a parameter
  1080. * entity, the name will begin with '%'.
  1081. * @throws SAXException The application may raise an exception.
  1082. * @see #endEntity
  1083. * @see org.xml.sax.ext.DeclHandler#internalEntityDecl
  1084. * @see org.xml.sax.ext.DeclHandler#externalEntityDecl
  1085. */
  1086. public void startEntity(String name) throws SAXException
  1087. {
  1088. if (null != m_resultLexicalHandler)
  1089. m_resultLexicalHandler.startEntity(name);
  1090. }
  1091. /**
  1092. * Report the end of an entity.
  1093. *
  1094. * @param name The name of the entity that is ending.
  1095. * @throws SAXException The application may raise an exception.
  1096. * @see #startEntity
  1097. */
  1098. public void endEntity(String name) throws SAXException
  1099. {
  1100. if (null != m_resultLexicalHandler)
  1101. m_resultLexicalHandler.endEntity(name);
  1102. }
  1103. /**
  1104. * Report the start of a CDATA section.
  1105. *
  1106. * <p>The contents of the CDATA section will be reported through
  1107. * the regular {@link org.xml.sax.ContentHandler#characters
  1108. * characters} event.</p>
  1109. *
  1110. * @throws SAXException The application may raise an exception.
  1111. * @see #endCDATA
  1112. */
  1113. public void startCDATA() throws SAXException
  1114. {
  1115. if (null != m_resultLexicalHandler)
  1116. m_resultLexicalHandler.startCDATA();
  1117. }
  1118. /**
  1119. * Report the end of a CDATA section.
  1120. *
  1121. * @throws SAXException The application may raise an exception.
  1122. * @see #startCDATA
  1123. */
  1124. public void endCDATA() throws SAXException
  1125. {
  1126. if (null != m_resultLexicalHandler)
  1127. m_resultLexicalHandler.endCDATA();
  1128. }
  1129. /**
  1130. * Report an XML comment anywhere in the document.
  1131. *
  1132. * <p>This callback will be used for comments inside or outside the
  1133. * document element, including comments in the external DTD
  1134. * subset (if read).</p>
  1135. *
  1136. * @param ch An array holding the characters in the comment.
  1137. * @param start The starting position in the array.
  1138. * @param length The number of characters to use from the array.
  1139. * @throws SAXException The application may raise an exception.
  1140. */
  1141. public void comment(char ch[], int start, int length) throws SAXException
  1142. {
  1143. flushStartDoc();
  1144. if (null != m_resultLexicalHandler)
  1145. m_resultLexicalHandler.comment(ch, start, length);
  1146. }
  1147. // Implement DeclHandler
  1148. /**
  1149. * Report an element type declaration.
  1150. *
  1151. * <p>The content model will consist of the string "EMPTY", the
  1152. * string "ANY", or a parenthesised group, optionally followed
  1153. * by an occurrence indicator. The model will be normalized so
  1154. * that all whitespace is removed,and will include the enclosing
  1155. * parentheses.</p>
  1156. *
  1157. * @param name The element type name.
  1158. * @param model The content model as a normalized string.
  1159. * @exception SAXException The application may raise an exception.
  1160. */
  1161. public void elementDecl (String name, String model)
  1162. throws SAXException
  1163. {
  1164. if (null != m_resultDeclHandler)
  1165. m_resultDeclHandler.elementDecl(name, model);
  1166. }
  1167. /**
  1168. * Report an attribute type declaration.
  1169. *
  1170. * <p>Only the effective (first) declaration for an attribute will
  1171. * be reported. The type will be one of the strings "CDATA",
  1172. * "ID", "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY",
  1173. * "ENTITIES", or "NOTATION", or a parenthesized token group with
  1174. * the separator "|" and all whitespace removed.</p>
  1175. *
  1176. * @param eName The name of the associated element.
  1177. * @param aName The name of the attribute.
  1178. * @param type A string representing the attribute type.
  1179. * @param valueDefault A string representing the attribute default
  1180. * ("#IMPLIED", "#REQUIRED", or "#FIXED") or null if
  1181. * none of these applies.
  1182. * @param value A string representing the attribute's default value,
  1183. * or null if there is none.
  1184. * @exception SAXException The application may raise an exception.
  1185. */
  1186. public void attributeDecl (String eName,
  1187. String aName,
  1188. String type,
  1189. String valueDefault,
  1190. String value)
  1191. throws SAXException
  1192. {
  1193. if (null != m_resultDeclHandler)
  1194. m_resultDeclHandler.attributeDecl(eName, aName, type, valueDefault, value);
  1195. }
  1196. /**
  1197. * Report an internal entity declaration.
  1198. *
  1199. * <p>Only the effective (first) declaration for each entity
  1200. * will be reported.</p>
  1201. *
  1202. * @param name The name of the entity. If it is a parameter
  1203. * entity, the name will begin with '%'.
  1204. * @param value The replacement text of the entity.
  1205. * @exception SAXException The application may raise an exception.
  1206. * @see #externalEntityDecl
  1207. * @see org.xml.sax.DTDHandler#unparsedEntityDecl
  1208. */
  1209. public void internalEntityDecl (String name, String value)
  1210. throws SAXException
  1211. {
  1212. if (null != m_resultDeclHandler)
  1213. m_resultDeclHandler.internalEntityDecl(name, value);
  1214. }
  1215. /**
  1216. * Report a parsed external entity declaration.
  1217. *
  1218. * <p>Only the effective (first) declaration for each entity
  1219. * will be reported.</p>
  1220. *
  1221. * @param name The name of the entity. If it is a parameter
  1222. * entity, the name will begin with '%'.
  1223. * @param publicId The declared public identifier of the entity, or
  1224. * null if none was declared.
  1225. * @param systemId The declared system identifier of the entity.
  1226. * @exception SAXException The application may raise an exception.
  1227. * @see #internalEntityDecl
  1228. * @see org.xml.sax.DTDHandler#unparsedEntityDecl
  1229. */
  1230. public void externalEntityDecl (String name, String publicId,
  1231. String systemId)
  1232. throws SAXException
  1233. {
  1234. if (null != m_resultDeclHandler)
  1235. m_resultDeclHandler.externalEntityDecl(name, publicId, systemId);
  1236. }
  1237. /**
  1238. * This is null unless we own the stream.
  1239. */
  1240. private java.io.FileOutputStream m_outputStream = null;
  1241. /** The content handler where result events will be sent. */
  1242. private ContentHandler m_resultContentHandler;
  1243. /** The lexical handler where result events will be sent. */
  1244. private LexicalHandler m_resultLexicalHandler;
  1245. /** The DTD handler where result events will be sent. */
  1246. private DTDHandler m_resultDTDHandler;
  1247. /** The Decl handler where result events will be sent. */
  1248. private DeclHandler m_resultDeclHandler;
  1249. /** The Serializer, which may or may not be null. */
  1250. private Serializer m_serializer;
  1251. /** The Result object. */
  1252. private Result m_result;
  1253. /**
  1254. * The system ID, which is unused, but must be returned to fullfill the
  1255. * TransformerHandler interface.
  1256. */
  1257. private String m_systemID;
  1258. /**
  1259. * The parameters, which is unused, but must be returned to fullfill the
  1260. * Transformer interface.
  1261. */
  1262. private Hashtable m_params;
  1263. /** The error listener for TrAX errors and warnings. */
  1264. private ErrorListener m_errorListener =
  1265. new org.apache.xml.utils.DefaultErrorHandler();
  1266. /**
  1267. * The URIResolver, which is unused, but must be returned to fullfill the
  1268. * TransformerHandler interface.
  1269. */
  1270. URIResolver m_URIResolver;
  1271. /** The output properties. */
  1272. private OutputProperties m_outputFormat;
  1273. /** Flag to set if we've found the first element, so we can tell if we have
  1274. * to check to see if we should create an HTML serializer. */
  1275. boolean m_foundFirstElement;
  1276. }