1 /* SAXNullTransformerFactory.java --
2 Copyright (C) 2001 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
40 import java.io.FileOutputStream;
41 import java.io.IOException;
42 import java.io.OutputStream;
44 import java.net.URLConnection;
45 import java.util.Hashtable;
46 import java.util.Properties;
48 import gnu.xml.dom.Consumer;
49 import gnu.xml.dom.DomDocument;
50 import gnu.xml.pipeline.DomConsumer;
51 import gnu.xml.pipeline.EventFilter;
53 import javax.xml.transform.*;
54 import javax.xml.transform.dom.*;
55 import javax.xml.transform.sax.*;
56 import javax.xml.transform.stream.*;
59 import org.xml.sax.helpers.XMLReaderFactory;
60 import org.xml.sax.helpers.LocatorImpl;
64 * Implements null transforms. XSLT stylesheets are not supported.
65 * This class provides a way to translate three representations of
66 * XML data (SAX event stream, DOM tree, and XML text) into each other.
67 * In essence it's a thinnish wrapper around basic SAX event
68 * <a href="../pipeline/package-summary.html">pipeline</a> facilities, which
69 * exposes only limited functionality. The <em>javax.xml.transform</em>
70 * functionality is implemented as follows: <ul>
72 * <li>The {@link javax.xml.transform.sax.SAXSource SAXSource} class
73 * just wraps an {@link XMLReader} and {@link InputSource}, while the
74 * {@link javax.xml.transform.sax.SAXResult SAXResult} class is less
75 * functional than a {@link gnu.xml.pipeline.EventConsumer EventConsumer}.
76 * (Notably, it drops all but one declaration from any DTD.)</li>
78 * <li>The {@link javax.xml.transform.dom.DOMSource DOMSource} class
79 * corresponds to special SAX parsers like {@link DomParser}, and the
80 * {@link javax.xml.transform.dom.DOMResult DOMResult} class corresponds
81 * to a {@link gnu.xml.pipeline.DomConsumer DomConsumer}.</li>
83 * <li>The {@link javax.xml.transform.stream.StreamSource StreamSource}
84 * class corresponds to a SAX {@link InputSource}, and the
85 * {@link javax.xml.transform.stream.StreamResult StreamResult} class
86 * corresponds to a {@link gnu.xml.pipeline.TextConsumer TextConsumer}.</li>
90 * <p><em>This implementation is preliminary.</em>
92 * @see gnu.xml.pipeline.XsltFilter
94 * @author David Brownell
96 public class SAXNullTransformerFactory extends SAXTransformerFactory
99 private ErrorListener errListener;
100 private URIResolver uriResolver;
102 /** Default constructor */
103 public SAXNullTransformerFactory () { }
106 // only has stuff that makes sense with null transforms
110 * Returns true if the requested feature is supported.
111 * All three kinds of input and output are accepted:
112 * XML text, SAX events, and DOM nodes.
114 public boolean getFeature (String feature)
116 return SAXTransformerFactory.FEATURE.equals (feature)
117 || SAXResult.FEATURE.equals (feature)
118 || SAXSource.FEATURE.equals (feature)
119 || DOMResult.FEATURE.equals (feature)
120 || DOMSource.FEATURE.equals (feature)
121 || StreamResult.FEATURE.equals (feature)
122 || StreamSource.FEATURE.equals (feature)
126 public void setFeature(String name, boolean value)
127 throws TransformerConfigurationException
129 throw new TransformerConfigurationException(name);
133 /** Throws an exception (no implementation attributes are supported) */
134 public void setAttribute (String key, Object value)
136 throw new IllegalArgumentException ();
139 /** Throws an exception (no implementation attributes are supported) */
140 public Object getAttribute (String key)
142 throw new IllegalArgumentException ();
145 /** (not yet implemented) */
146 public Source getAssociatedStylesheet (Source source,
150 throws TransformerConfigurationException
152 // parse, and find the appropriate xsl-stylesheet PI contents
153 throw new IllegalArgumentException ();
156 public Transformer newTransformer ()
157 throws TransformerConfigurationException
159 return new NullTransformer ();
163 * Returns a TransformerHandler that knows how to generate output
164 * in all three standard formats. Output text is generated using
165 * {@link XMLWriter}, and the GNU implementation of
166 * {@link DomDocument DOM} is used.
172 public TransformerHandler newTransformerHandler ()
173 throws TransformerConfigurationException
175 NullTransformer transformer = new NullTransformer ();
176 return transformer.handler;
180 // Stuff that depends on XSLT support, which we don't provide
182 private static final String noXSLT = "No XSLT support";
184 /** Throws an exception (XSLT is not supported). */
185 public Transformer newTransformer (Source stylesheet)
186 throws TransformerConfigurationException
188 throw new TransformerConfigurationException (noXSLT);
191 /** Throws an exception (XSLT is not supported). */
192 public Templates newTemplates (Source stylesheet)
193 throws TransformerConfigurationException
195 throw new TransformerConfigurationException (noXSLT);
198 /** Throws an exception (XSLT is not supported). */
199 public TemplatesHandler newTemplatesHandler ()
200 throws TransformerConfigurationException
202 throw new TransformerConfigurationException (noXSLT);
205 /** Throws an exception (XSLT is not supported). */
206 public TransformerHandler newTransformerHandler (Source stylesheet)
207 throws TransformerConfigurationException
209 throw new TransformerConfigurationException (noXSLT);
212 /** Throws an exception (XSLT is not supported). */
213 public TransformerHandler newTransformerHandler (Templates stylesheet)
214 throws TransformerConfigurationException
216 throw new TransformerConfigurationException (noXSLT);
219 /** Throws an exception (XSLT is not supported). */
220 public XMLFilter newXMLFilter (Source stylesheet)
221 throws TransformerConfigurationException
223 throw new TransformerConfigurationException (noXSLT);
226 /** Throws an exception (XSLT is not supported). */
227 public XMLFilter newXMLFilter (Templates stylesheet)
228 throws TransformerConfigurationException
230 throw new TransformerConfigurationException (noXSLT);
233 /** Returns the value assigned by {@link #setErrorListener}. */
234 public ErrorListener getErrorListener ()
239 /** Assigns a value that would be used when parsing stylesheets */
240 public void setErrorListener (ErrorListener e)
245 /** Returns the value assigned by {@link #setURIResolver}. */
246 public URIResolver getURIResolver ()
251 /** Assigns a value that would be used when parsing stylesheets */
252 public void setURIResolver (URIResolver u)
259 // Helper classes. These might in theory be subclassed
260 // by an XSLT implementation, if they were exported.
263 static class DomTerminus
267 DomTerminus (DOMResult result)
270 // won't really throw SAXException
271 super (DomDocument.class);
272 setHandler (new DomHandler (this, result));
277 static class DomHandler
278 extends Consumer.Backdoor
281 private DOMResult result;
283 DomHandler (DomConsumer c, DOMResult r)
286 // won't really throw SAXException
291 public void endDocument ()
294 super.endDocument ();
295 result.setNode (getDocument ());
300 private static OutputStream getOutputStream (String uri)
303 // JDK stupidity: file "protocol does not support output" ...
304 if (uri.startsWith ("file:"))
305 return new FileOutputStream (uri.substring (5));
308 URL url = new URL (uri);
309 URLConnection conn = url.openConnection ();
311 conn.setDoOutput (true);
312 return conn.getOutputStream ();
316 static class NullHandler
318 implements TransformerHandler
321 private String systemId;
322 private Transformer transformer;
324 NullHandler (Transformer t)
329 public Transformer getTransformer ()
334 public String getSystemId ()
339 public void setSystemId (String id)
344 public void setResult (Result result)
346 if (result.getSystemId () != null)
347 systemId = result.getSystemId ();
352 // output to partial SAX event stream?
353 if (result instanceof SAXResult)
355 SAXResult r = (SAXResult) result;
357 setContentHandler (r.getHandler ());
358 setProperty (LEXICAL_HANDLER, r.getLexicalHandler ());
359 // DTD info is filtered out by javax.transform
361 // output to DOM tree?
363 else if (result instanceof DOMResult)
365 DomTerminus out = new DomTerminus ((DOMResult) result);
367 setContentHandler (out.getContentHandler ());
368 setProperty (LEXICAL_HANDLER,
369 out.getProperty (LEXICAL_HANDLER));
370 // save DTD-derived info, if any.
371 setDTDHandler (out.getDTDHandler ());
372 setProperty (DECL_HANDLER,
373 out.getProperty (DECL_HANDLER));
375 // node is saved into result on endDocument()
377 // output to (XML) text?
379 else if (result instanceof StreamResult)
381 StreamResult r = (StreamResult) result;
384 // FIXME: when do output properties take effect?
385 // encoding, standalone decl, xml/xhtml/... ...
387 // FIXME: maybe put nsfix filter up front
391 if (r.getWriter () != null)
392 out = new XMLWriter (r.getWriter ());
393 else if (r.getOutputStream () != null)
394 out = new XMLWriter (r.getOutputStream ());
395 else if (r.getSystemId () != null)
396 out = new XMLWriter (
397 getOutputStream (r.getSystemId ()));
399 throw new IllegalArgumentException (
402 catch (IOException e)
404 e.printStackTrace ();
405 // on jdk 1.4, pass the root cause ...
406 throw new IllegalArgumentException (e.getMessage ());
409 // out.setExpandingEntities (true);
410 // out.setPrettyPrinting (true);
411 // out.setXhtml (true);
413 setContentHandler (out);
414 setProperty (LEXICAL_HANDLER, out);
415 // save DTD info, if any; why not?
417 setProperty (DECL_HANDLER, out);
421 catch (SAXException e)
423 // SAXNotSupportedException or SAXNotRecognizedException:
424 // "can't happen" ... but SAXException for DOM build probs
425 // could happen, so ...
426 // on jdk 1.4, pass the root cause ...
427 throw new IllegalArgumentException (e.getMessage ());
432 // an interface that adds no value
433 static class LocatorAdapter
435 implements SourceLocator
438 LocatorAdapter (SAXParseException e)
440 setSystemId (e.getSystemId ());
441 setPublicId (e.getPublicId ());
442 setLineNumber (e.getLineNumber ());
443 setColumnNumber (e.getColumnNumber ());
448 // another interface that adds no value
449 static class ListenerAdapter
450 implements ErrorHandler
453 NullTransformer transformer;
455 ListenerAdapter (NullTransformer t)
460 private TransformerException map (SAXParseException e)
462 return new TransformerException (
464 new LocatorAdapter (e),
468 public void error (SAXParseException e)
469 throws SAXParseException
473 if (transformer.errListener != null)
474 transformer.errListener.error (map (e));
476 catch (TransformerException ex)
483 public void fatalError (SAXParseException e)
484 throws SAXParseException
488 if (transformer.errListener != null)
489 transformer.errListener.fatalError (map (e));
492 } catch (TransformerException ex) {
498 public void warning (SAXParseException e)
499 throws SAXParseException
503 if (transformer.errListener != null)
504 transformer.errListener.warning (map (e));
506 catch (TransformerException ex)
514 static class NullTransformer
518 private URIResolver uriResolver;
519 private Properties props = new Properties ();
520 private Hashtable params = new Hashtable (7);
522 ErrorListener errListener = null;
523 TransformerException ex = null;
529 handler = new NullHandler (this);
532 public ErrorListener getErrorListener ()
537 public void setErrorListener (ErrorListener e)
542 public URIResolver getURIResolver ()
547 public void setURIResolver (URIResolver u)
552 public void setOutputProperties (Properties p)
554 props = (Properties) p.clone ();
557 public Properties getOutputProperties ()
559 return (Properties) props.clone ();
562 public void setOutputProperty (String name, String value)
564 props.setProperty (name, value);
567 public String getOutputProperty (String name)
569 return props.getProperty (name);
572 public void clearParameters ()
577 public void setParameter (String name, Object value)
579 props.put (name, value);
582 public Object getParameter (String name)
584 return props.get (name);
587 public void transform (Source in, Result out)
588 throws TransformerException
596 if (in instanceof DOMSource)
598 DOMSource source = (DOMSource) in;
600 if (source.getNode () == null)
601 throw new IllegalArgumentException ("no DOM node");
602 producer = new DomParser (source.getNode ());
607 else if (in instanceof SAXSource)
609 SAXSource source = (SAXSource) in;
611 producer = source.getXMLReader ();
612 if (producer == null)
613 producer = XMLReaderFactory.createXMLReader ();
615 input = source.getInputSource ();
618 if (source.getSystemId () != null)
619 input = new InputSource (source.getSystemId ());
621 throw new IllegalArgumentException (
622 "missing SAX input");
625 // Input from a stream or something?
629 producer = XMLReaderFactory.createXMLReader ();
630 input = SAXSource.sourceToInputSource (in);
632 throw new IllegalArgumentException ("missing input");
635 // preserve original namespace prefixes
638 producer.setFeature(handler.FEATURE_URI + "namespace-prefixes",
644 // FIXME if we couldn't, "NsFix" stage before the output ..
647 // arrange the output
648 handler.setResult (out);
649 handler.bind (producer, handler);
651 // then parse ... single element pipeline
652 producer.parse (input);
655 catch (IOException e)
657 throw new TransformerException ("transform failed", e);
660 catch (SAXException e)
662 if (ex == null && ex.getCause () == e)
665 throw new TransformerException ("transform failed", e);