SAXNullTransformerFactory.java 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. /* SAXNullTransformerFactory.java --
  2. Copyright (C) 2001 Free Software Foundation, Inc.
  3. This file is part of GNU Classpath.
  4. GNU Classpath is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.
  8. GNU Classpath is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Classpath; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  15. 02110-1301 USA.
  16. Linking this library statically or dynamically with other modules is
  17. making a combined work based on this library. Thus, the terms and
  18. conditions of the GNU General Public License cover the whole
  19. combination.
  20. As a special exception, the copyright holders of this library give you
  21. permission to link this library with independent modules to produce an
  22. executable, regardless of the license terms of these independent
  23. modules, and to copy and distribute the resulting executable under
  24. terms of your choice, provided that you also meet, for each linked
  25. independent module, the terms and conditions of the license of that
  26. module. An independent module is a module which is not derived from
  27. or based on this library. If you modify this library, you may extend
  28. this exception to your version of the library, but you are not
  29. obligated to do so. If you do not wish to do so, delete this
  30. exception statement from your version. */
  31. package gnu.xml.util;
  32. import java.io.FileOutputStream;
  33. import java.io.IOException;
  34. import java.io.OutputStream;
  35. import java.net.URL;
  36. import java.net.URLConnection;
  37. import java.util.Hashtable;
  38. import java.util.Properties;
  39. import gnu.xml.dom.Consumer;
  40. import gnu.xml.dom.DomDocument;
  41. import gnu.xml.pipeline.DomConsumer;
  42. import gnu.xml.pipeline.EventFilter;
  43. import javax.xml.transform.*;
  44. import javax.xml.transform.dom.*;
  45. import javax.xml.transform.sax.*;
  46. import javax.xml.transform.stream.*;
  47. import org.xml.sax.*;
  48. import org.xml.sax.helpers.XMLReaderFactory;
  49. import org.xml.sax.helpers.LocatorImpl;
  50. /**
  51. * Implements null transforms. XSLT stylesheets are not supported.
  52. * This class provides a way to translate three representations of
  53. * XML data (SAX event stream, DOM tree, and XML text) into each other.
  54. * In essence it's a thinnish wrapper around basic SAX event
  55. * <a href="../pipeline/package-summary.html">pipeline</a> facilities, which
  56. * exposes only limited functionality. The <em>javax.xml.transform</em>
  57. * functionality is implemented as follows: <ul>
  58. *
  59. * <li>The {@link javax.xml.transform.sax.SAXSource SAXSource} class
  60. * just wraps an {@link XMLReader} and {@link InputSource}, while the
  61. * {@link javax.xml.transform.sax.SAXResult SAXResult} class is less
  62. * functional than a {@link gnu.xml.pipeline.EventConsumer EventConsumer}.
  63. * (Notably, it drops all but one declaration from any DTD.)</li>
  64. *
  65. * <li>The {@link javax.xml.transform.dom.DOMSource DOMSource} class
  66. * corresponds to special SAX parsers like {@link DomParser}, and the
  67. * {@link javax.xml.transform.dom.DOMResult DOMResult} class corresponds
  68. * to a {@link gnu.xml.pipeline.DomConsumer DomConsumer}.</li>
  69. *
  70. * <li>The {@link javax.xml.transform.stream.StreamSource StreamSource}
  71. * class corresponds to a SAX {@link InputSource}, and the
  72. * {@link javax.xml.transform.stream.StreamResult StreamResult} class
  73. * corresponds to a {@link gnu.xml.pipeline.TextConsumer TextConsumer}.</li>
  74. *
  75. * </ul>
  76. *
  77. * <p><em>This implementation is preliminary.</em>
  78. *
  79. * @see gnu.xml.pipeline.XsltFilter
  80. *
  81. * @author David Brownell
  82. */
  83. public class SAXNullTransformerFactory extends SAXTransformerFactory
  84. {
  85. private ErrorListener errListener;
  86. private URIResolver uriResolver;
  87. /** Default constructor */
  88. public SAXNullTransformerFactory () { }
  89. //
  90. // only has stuff that makes sense with null transforms
  91. //
  92. /**
  93. * Returns true if the requested feature is supported.
  94. * All three kinds of input and output are accepted:
  95. * XML text, SAX events, and DOM nodes.
  96. */
  97. public boolean getFeature (String feature)
  98. {
  99. return SAXTransformerFactory.FEATURE.equals (feature)
  100. || SAXResult.FEATURE.equals (feature)
  101. || SAXSource.FEATURE.equals (feature)
  102. || DOMResult.FEATURE.equals (feature)
  103. || DOMSource.FEATURE.equals (feature)
  104. || StreamResult.FEATURE.equals (feature)
  105. || StreamSource.FEATURE.equals (feature)
  106. ;
  107. }
  108. public void setFeature(String name, boolean value)
  109. throws TransformerConfigurationException
  110. {
  111. throw new TransformerConfigurationException(name);
  112. }
  113. /** Throws an exception (no implementation attributes are supported) */
  114. public void setAttribute (String key, Object value)
  115. {
  116. throw new IllegalArgumentException ();
  117. }
  118. /** Throws an exception (no implementation attributes are supported) */
  119. public Object getAttribute (String key)
  120. {
  121. throw new IllegalArgumentException ();
  122. }
  123. /** (not yet implemented) */
  124. public Source getAssociatedStylesheet (Source source,
  125. String media,
  126. String title,
  127. String charset)
  128. throws TransformerConfigurationException
  129. {
  130. // parse, and find the appropriate xsl-stylesheet PI contents
  131. throw new IllegalArgumentException ();
  132. }
  133. public Transformer newTransformer ()
  134. throws TransformerConfigurationException
  135. {
  136. return new NullTransformer ();
  137. }
  138. /**
  139. * Returns a TransformerHandler that knows how to generate output
  140. * in all three standard formats. Output text is generated using
  141. * {@link XMLWriter}, and the GNU implementation of
  142. * {@link DomDocument DOM} is used.
  143. *
  144. * @see SAXResult
  145. * @see StreamResult
  146. * @see DOMResult
  147. */
  148. public TransformerHandler newTransformerHandler ()
  149. throws TransformerConfigurationException
  150. {
  151. NullTransformer transformer = new NullTransformer ();
  152. return transformer.handler;
  153. }
  154. //
  155. // Stuff that depends on XSLT support, which we don't provide
  156. //
  157. private static final String noXSLT = "No XSLT support";
  158. /** Throws an exception (XSLT is not supported). */
  159. public Transformer newTransformer (Source stylesheet)
  160. throws TransformerConfigurationException
  161. {
  162. throw new TransformerConfigurationException (noXSLT);
  163. }
  164. /** Throws an exception (XSLT is not supported). */
  165. public Templates newTemplates (Source stylesheet)
  166. throws TransformerConfigurationException
  167. {
  168. throw new TransformerConfigurationException (noXSLT);
  169. }
  170. /** Throws an exception (XSLT is not supported). */
  171. public TemplatesHandler newTemplatesHandler ()
  172. throws TransformerConfigurationException
  173. {
  174. throw new TransformerConfigurationException (noXSLT);
  175. }
  176. /** Throws an exception (XSLT is not supported). */
  177. public TransformerHandler newTransformerHandler (Source stylesheet)
  178. throws TransformerConfigurationException
  179. {
  180. throw new TransformerConfigurationException (noXSLT);
  181. }
  182. /** Throws an exception (XSLT is not supported). */
  183. public TransformerHandler newTransformerHandler (Templates stylesheet)
  184. throws TransformerConfigurationException
  185. {
  186. throw new TransformerConfigurationException (noXSLT);
  187. }
  188. /** Throws an exception (XSLT is not supported). */
  189. public XMLFilter newXMLFilter (Source stylesheet)
  190. throws TransformerConfigurationException
  191. {
  192. throw new TransformerConfigurationException (noXSLT);
  193. }
  194. /** Throws an exception (XSLT is not supported). */
  195. public XMLFilter newXMLFilter (Templates stylesheet)
  196. throws TransformerConfigurationException
  197. {
  198. throw new TransformerConfigurationException (noXSLT);
  199. }
  200. /** Returns the value assigned by {@link #setErrorListener}. */
  201. public ErrorListener getErrorListener ()
  202. {
  203. return errListener;
  204. }
  205. /** Assigns a value that would be used when parsing stylesheets */
  206. public void setErrorListener (ErrorListener e)
  207. {
  208. errListener = e;
  209. }
  210. /** Returns the value assigned by {@link #setURIResolver}. */
  211. public URIResolver getURIResolver ()
  212. {
  213. return uriResolver;
  214. }
  215. /** Assigns a value that would be used when parsing stylesheets */
  216. public void setURIResolver (URIResolver u)
  217. {
  218. uriResolver = u;
  219. }
  220. //
  221. // Helper classes. These might in theory be subclassed
  222. // by an XSLT implementation, if they were exported.
  223. //
  224. static class DomTerminus
  225. extends DomConsumer
  226. {
  227. DomTerminus (DOMResult result)
  228. throws SAXException
  229. {
  230. // won't really throw SAXException
  231. super (DomDocument.class);
  232. setHandler (new DomHandler (this, result));
  233. }
  234. }
  235. static class DomHandler
  236. extends Consumer.Backdoor
  237. {
  238. private DOMResult result;
  239. DomHandler (DomConsumer c, DOMResult r)
  240. throws SAXException
  241. {
  242. // won't really throw SAXException
  243. super (c);
  244. result = r;
  245. }
  246. public void endDocument ()
  247. throws SAXException
  248. {
  249. super.endDocument ();
  250. result.setNode (getDocument ());
  251. }
  252. }
  253. private static OutputStream getOutputStream (String uri)
  254. throws IOException
  255. {
  256. // JDK stupidity: file "protocol does not support output" ...
  257. if (uri.startsWith ("file:"))
  258. return new FileOutputStream (uri.substring (5));
  259. // Otherwise ...
  260. URL url = new URL (uri);
  261. URLConnection conn = url.openConnection ();
  262. conn.setDoOutput (true);
  263. return conn.getOutputStream ();
  264. }
  265. static class NullHandler
  266. extends EventFilter
  267. implements TransformerHandler
  268. {
  269. private String systemId;
  270. private Transformer transformer;
  271. NullHandler (Transformer t)
  272. {
  273. transformer = t;
  274. }
  275. public Transformer getTransformer ()
  276. {
  277. return transformer;
  278. }
  279. public String getSystemId ()
  280. {
  281. return systemId;
  282. }
  283. public void setSystemId (String id)
  284. {
  285. systemId = id;
  286. }
  287. public void setResult (Result result)
  288. {
  289. if (result.getSystemId () != null)
  290. systemId = result.getSystemId ();
  291. try
  292. {
  293. // output to partial SAX event stream?
  294. if (result instanceof SAXResult)
  295. {
  296. SAXResult r = (SAXResult) result;
  297. setContentHandler (r.getHandler ());
  298. setProperty (LEXICAL_HANDLER, r.getLexicalHandler ());
  299. // DTD info is filtered out by javax.transform
  300. // output to DOM tree?
  301. }
  302. else if (result instanceof DOMResult)
  303. {
  304. DomTerminus out = new DomTerminus ((DOMResult) result);
  305. setContentHandler (out.getContentHandler ());
  306. setProperty (LEXICAL_HANDLER,
  307. out.getProperty (LEXICAL_HANDLER));
  308. // save DTD-derived info, if any.
  309. setDTDHandler (out.getDTDHandler ());
  310. setProperty (DECL_HANDLER,
  311. out.getProperty (DECL_HANDLER));
  312. // node is saved into result on endDocument()
  313. // output to (XML) text?
  314. }
  315. else if (result instanceof StreamResult)
  316. {
  317. StreamResult r = (StreamResult) result;
  318. XMLWriter out;
  319. // FIXME: when do output properties take effect?
  320. // encoding, standalone decl, xml/xhtml/... ...
  321. // FIXME: maybe put nsfix filter up front
  322. try
  323. {
  324. if (r.getWriter () != null)
  325. out = new XMLWriter (r.getWriter ());
  326. else if (r.getOutputStream () != null)
  327. out = new XMLWriter (r.getOutputStream ());
  328. else if (r.getSystemId () != null)
  329. out = new XMLWriter (
  330. getOutputStream (r.getSystemId ()));
  331. else
  332. throw new IllegalArgumentException (
  333. "bad StreamResult");
  334. }
  335. catch (IOException e)
  336. {
  337. e.printStackTrace ();
  338. // on jdk 1.4, pass the root cause ...
  339. throw new IllegalArgumentException (e.getMessage ());
  340. }
  341. // out.setExpandingEntities (true);
  342. // out.setPrettyPrinting (true);
  343. // out.setXhtml (true);
  344. setContentHandler (out);
  345. setProperty (LEXICAL_HANDLER, out);
  346. // save DTD info, if any; why not?
  347. setDTDHandler (out);
  348. setProperty (DECL_HANDLER, out);
  349. }
  350. }
  351. catch (SAXException e)
  352. {
  353. // SAXNotSupportedException or SAXNotRecognizedException:
  354. // "can't happen" ... but SAXException for DOM build probs
  355. // could happen, so ...
  356. // on jdk 1.4, pass the root cause ...
  357. throw new IllegalArgumentException (e.getMessage ());
  358. }
  359. }
  360. }
  361. // an interface that adds no value
  362. static class LocatorAdapter
  363. extends LocatorImpl
  364. implements SourceLocator
  365. {
  366. LocatorAdapter (SAXParseException e)
  367. {
  368. setSystemId (e.getSystemId ());
  369. setPublicId (e.getPublicId ());
  370. setLineNumber (e.getLineNumber ());
  371. setColumnNumber (e.getColumnNumber ());
  372. }
  373. }
  374. // another interface that adds no value
  375. static class ListenerAdapter
  376. implements ErrorHandler
  377. {
  378. NullTransformer transformer;
  379. ListenerAdapter (NullTransformer t)
  380. {
  381. transformer = t;
  382. }
  383. private TransformerException map (SAXParseException e)
  384. {
  385. return new TransformerException (
  386. e.getMessage (),
  387. new LocatorAdapter (e),
  388. e);
  389. }
  390. public void error (SAXParseException e)
  391. throws SAXParseException
  392. {
  393. try
  394. {
  395. if (transformer.errListener != null)
  396. transformer.errListener.error (map (e));
  397. }
  398. catch (TransformerException ex)
  399. {
  400. transformer.ex = ex;
  401. throw e;
  402. }
  403. }
  404. public void fatalError (SAXParseException e)
  405. throws SAXParseException
  406. {
  407. try
  408. {
  409. if (transformer.errListener != null)
  410. transformer.errListener.fatalError (map (e));
  411. else
  412. throw map (e);
  413. } catch (TransformerException ex) {
  414. transformer.ex = ex;
  415. throw e;
  416. }
  417. }
  418. public void warning (SAXParseException e)
  419. throws SAXParseException
  420. {
  421. try
  422. {
  423. if (transformer.errListener != null)
  424. transformer.errListener.warning (map (e));
  425. }
  426. catch (TransformerException ex)
  427. {
  428. transformer.ex = ex;
  429. throw e;
  430. }
  431. }
  432. }
  433. static class NullTransformer
  434. extends Transformer
  435. {
  436. private URIResolver uriResolver;
  437. private Properties props = new Properties ();
  438. private Hashtable params = new Hashtable (7);
  439. ErrorListener errListener = null;
  440. TransformerException ex = null;
  441. NullHandler handler;
  442. NullTransformer ()
  443. {
  444. super ();
  445. handler = new NullHandler (this);
  446. }
  447. public ErrorListener getErrorListener ()
  448. {
  449. return errListener;
  450. }
  451. public void setErrorListener (ErrorListener e)
  452. {
  453. errListener = e;
  454. }
  455. public URIResolver getURIResolver ()
  456. {
  457. return uriResolver;
  458. }
  459. public void setURIResolver (URIResolver u)
  460. {
  461. uriResolver = u;
  462. }
  463. public void setOutputProperties (Properties p)
  464. {
  465. props = (Properties) p.clone ();
  466. }
  467. public Properties getOutputProperties ()
  468. {
  469. return (Properties) props.clone ();
  470. }
  471. public void setOutputProperty (String name, String value)
  472. {
  473. props.setProperty (name, value);
  474. }
  475. public String getOutputProperty (String name)
  476. {
  477. return props.getProperty (name);
  478. }
  479. public void clearParameters ()
  480. {
  481. params.clear ();
  482. }
  483. public void setParameter (String name, Object value)
  484. {
  485. props.put (name, value);
  486. }
  487. public Object getParameter (String name)
  488. {
  489. return props.get (name);
  490. }
  491. public void transform (Source in, Result out)
  492. throws TransformerException
  493. {
  494. try
  495. {
  496. XMLReader producer;
  497. InputSource input;
  498. // Input from DOM?
  499. if (in instanceof DOMSource)
  500. {
  501. DOMSource source = (DOMSource) in;
  502. if (source.getNode () == null)
  503. throw new IllegalArgumentException ("no DOM node");
  504. producer = new DomParser (source.getNode ());
  505. input = null;
  506. // Input from SAX?
  507. }
  508. else if (in instanceof SAXSource)
  509. {
  510. SAXSource source = (SAXSource) in;
  511. producer = source.getXMLReader ();
  512. if (producer == null)
  513. producer = XMLReaderFactory.createXMLReader ();
  514. input = source.getInputSource ();
  515. if (input == null)
  516. {
  517. if (source.getSystemId () != null)
  518. input = new InputSource (source.getSystemId ());
  519. else
  520. throw new IllegalArgumentException (
  521. "missing SAX input");
  522. }
  523. // Input from a stream or something?
  524. }
  525. else
  526. {
  527. producer = XMLReaderFactory.createXMLReader ();
  528. input = SAXSource.sourceToInputSource (in);
  529. if (input == null)
  530. throw new IllegalArgumentException ("missing input");
  531. }
  532. // preserve original namespace prefixes
  533. try
  534. {
  535. producer.setFeature(EventFilter.FEATURE_URI +
  536. "namespace-prefixes",
  537. true);
  538. }
  539. catch (Exception e)
  540. {
  541. /* ignore */
  542. // FIXME if we couldn't, "NsFix" stage before the output ..
  543. }
  544. // arrange the output
  545. handler.setResult (out);
  546. EventFilter.bind (producer, handler);
  547. // then parse ... single element pipeline
  548. producer.parse (input);
  549. }
  550. catch (IOException e)
  551. {
  552. throw new TransformerException ("transform failed", e);
  553. }
  554. catch (SAXException e)
  555. {
  556. if (ex == null && ex.getCause () == e)
  557. throw ex;
  558. else
  559. throw new TransformerException ("transform failed", e);
  560. }
  561. finally
  562. {
  563. ex = null;
  564. }
  565. }
  566. }
  567. }