OSDN Git Service

* external/w3c_dom/Makefile.am: New file.
[pf3gnuchains/gcc-fork.git] / libjava / gnu / xml / util / SAXNullTransformerFactory.java
1 /* SAXNullTransformerFactory.java -- 
2    Copyright (C) 2001 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
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)
9 any later version.
10
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.
15
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
19 02111-1307 USA.
20
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
24 combination.
25
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. */
37
38 package gnu.xml.util;
39
40 import java.io.FileOutputStream;
41 import java.io.IOException;
42 import java.io.OutputStream;
43 import java.net.URL;
44 import java.net.URLConnection;
45 import java.util.Hashtable;
46 import java.util.Properties;
47
48 import gnu.xml.dom.Consumer;
49 import gnu.xml.dom.DomDocument;
50 import gnu.xml.pipeline.DomConsumer;
51 import gnu.xml.pipeline.EventFilter;
52
53 import javax.xml.transform.*;
54 import javax.xml.transform.dom.*;
55 import javax.xml.transform.sax.*;
56 import javax.xml.transform.stream.*;
57
58 import org.xml.sax.*;
59 import org.xml.sax.helpers.XMLReaderFactory;
60 import org.xml.sax.helpers.LocatorImpl;
61
62
63 /**
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>
71  *
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>
77  *
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>
82  *
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>
87  *
88  * </ul>
89  *
90  * <p><em>This implementation is preliminary.</em>
91  *
92  * @see gnu.xml.pipeline.XsltFilter
93  *
94  * @author David Brownell
95  */
96 public class SAXNullTransformerFactory extends SAXTransformerFactory
97 {
98   
99   private ErrorListener errListener;
100   private URIResolver           uriResolver;
101   
102   /** Default constructor */
103   public SAXNullTransformerFactory () { }
104   
105   //
106   // only has stuff that makes sense with null transforms
107   //
108   
109   /**
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.
113    */
114   public boolean getFeature (String feature)
115   {
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)
123       ;
124   }
125
126   public void setFeature(String name, boolean value)
127     throws TransformerConfigurationException
128   {
129     throw new TransformerConfigurationException(name);
130   }
131
132
133   /** Throws an exception (no implementation attributes are supported) */
134   public void setAttribute (String key, Object value)
135   {
136     throw new IllegalArgumentException ();
137   }
138
139   /** Throws an exception (no implementation attributes are supported) */
140   public Object getAttribute (String key)
141   {
142     throw new IllegalArgumentException ();
143   }
144
145   /** (not yet implemented) */
146   public Source getAssociatedStylesheet (Source source,
147                                          String media,
148                                          String title,
149                                          String charset)
150     throws TransformerConfigurationException
151   {
152     // parse, and find the appropriate xsl-stylesheet PI contents
153     throw new IllegalArgumentException ();
154   }
155
156   public Transformer newTransformer ()
157     throws TransformerConfigurationException
158   {
159     return new NullTransformer ();
160   }
161
162   /**
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.
167    *
168    * @see SAXResult
169    * @see StreamResult
170    * @see DOMResult
171    */
172   public TransformerHandler newTransformerHandler ()
173     throws TransformerConfigurationException
174   {
175     NullTransformer     transformer = new NullTransformer ();
176     return transformer.handler;
177   }
178
179   //
180   // Stuff that depends on XSLT support, which we don't provide
181   //
182   private static final String           noXSLT = "No XSLT support";
183
184   /** Throws an exception (XSLT is not supported). */
185   public Transformer newTransformer (Source stylesheet)
186     throws TransformerConfigurationException
187   {
188     throw new TransformerConfigurationException (noXSLT);
189   }
190
191   /** Throws an exception (XSLT is not supported). */
192   public Templates newTemplates (Source stylesheet)
193     throws TransformerConfigurationException
194   {
195     throw new TransformerConfigurationException (noXSLT);
196   }
197
198   /** Throws an exception (XSLT is not supported). */
199   public TemplatesHandler newTemplatesHandler ()
200     throws TransformerConfigurationException
201   {
202     throw new TransformerConfigurationException (noXSLT);
203   }
204
205   /** Throws an exception (XSLT is not supported). */
206   public TransformerHandler newTransformerHandler (Source stylesheet)
207     throws TransformerConfigurationException
208   {
209     throw new TransformerConfigurationException (noXSLT);
210   }
211
212   /** Throws an exception (XSLT is not supported). */
213   public TransformerHandler newTransformerHandler (Templates stylesheet)
214     throws TransformerConfigurationException
215   {
216     throw new TransformerConfigurationException (noXSLT);
217   }
218
219   /** Throws an exception (XSLT is not supported). */
220   public XMLFilter newXMLFilter (Source stylesheet)
221     throws TransformerConfigurationException
222   {
223     throw new TransformerConfigurationException (noXSLT);
224   }
225
226   /** Throws an exception (XSLT is not supported). */
227   public XMLFilter newXMLFilter (Templates stylesheet)
228     throws TransformerConfigurationException
229   {
230     throw new TransformerConfigurationException (noXSLT);
231   }
232
233   /** Returns the value assigned by {@link #setErrorListener}.  */
234   public ErrorListener getErrorListener ()
235   {
236     return errListener;
237   }
238
239   /** Assigns a value that would be used when parsing stylesheets */
240   public void setErrorListener (ErrorListener e)
241   {
242     errListener = e;
243   }
244
245   /** Returns the value assigned by {@link #setURIResolver}.  */
246   public URIResolver getURIResolver ()
247   {
248     return uriResolver;
249   }
250
251   /** Assigns a value that would be used when parsing stylesheets */
252   public void setURIResolver (URIResolver u)
253   {
254     uriResolver = u;
255   }
256
257
258   //
259   // Helper classes.  These might in theory be subclassed
260   // by an XSLT implementation, if they were exported.
261   //
262
263   static class DomTerminus
264     extends DomConsumer
265   {
266
267     DomTerminus (DOMResult result)
268       throws SAXException
269     {
270       // won't really throw SAXException
271       super (DomDocument.class);
272       setHandler (new DomHandler (this, result));
273     }
274     
275   }
276
277   static class DomHandler
278     extends Consumer.Backdoor
279   {
280   
281     private DOMResult   result;
282     
283     DomHandler (DomConsumer c, DOMResult r)
284       throws SAXException
285     {
286       // won't really throw SAXException
287       super (c);
288       result = r;
289     }
290
291     public void endDocument ()
292       throws SAXException
293     {
294       super.endDocument ();
295       result.setNode (getDocument ());
296     }
297     
298   }
299
300   private static OutputStream getOutputStream (String uri)
301     throws IOException
302   {
303     // JDK stupidity:  file "protocol does not support output" ... 
304     if (uri.startsWith ("file:"))
305       return new FileOutputStream (uri.substring (5));
306     
307     // Otherwise ...
308     URL         url = new URL (uri);
309     URLConnection       conn = url.openConnection ();
310     
311     conn.setDoOutput (true);
312     return conn.getOutputStream ();
313   }
314   
315
316   static class NullHandler
317     extends EventFilter
318     implements TransformerHandler
319   {
320    
321     private String              systemId;
322     private Transformer transformer;
323     
324     NullHandler (Transformer t)
325     {
326       transformer = t;
327     }
328
329     public Transformer getTransformer ()
330     {
331       return transformer;
332     }
333
334     public String getSystemId ()
335     {
336       return systemId;
337     }
338
339     public void setSystemId (String id)
340     {
341       systemId = id;
342     }
343
344     public void setResult (Result result)
345     {
346       if (result.getSystemId () != null)
347         systemId = result.getSystemId ();
348       
349       try
350         {
351           
352           // output to partial SAX event stream?
353           if (result instanceof SAXResult)
354             {
355               SAXResult         r = (SAXResult) result;
356               
357               setContentHandler (r.getHandler ());
358               setProperty (LEXICAL_HANDLER, r.getLexicalHandler ());
359               // DTD info is filtered out by javax.transform
360               
361               // output to DOM tree?
362             }
363           else if (result instanceof DOMResult)
364             {
365               DomTerminus       out = new DomTerminus ((DOMResult) result);
366
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));
374
375               // node is saved into result on endDocument()
376
377               // output to (XML) text?
378             }
379           else if (result instanceof StreamResult)
380             {
381               StreamResult      r = (StreamResult) result;
382               XMLWriter         out;
383
384               // FIXME:  when do output properties take effect?
385               // encoding, standalone decl, xml/xhtml/... ...
386
387               // FIXME:  maybe put nsfix filter up front
388
389               try
390                 {
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 ()));
398                   else
399                     throw new IllegalArgumentException (
400                                                         "bad StreamResult");
401                 }
402               catch (IOException e)
403                 {
404                   e.printStackTrace ();
405                   // on jdk 1.4, pass the root cause ...
406                   throw new IllegalArgumentException (e.getMessage ());
407                 }
408
409               // out.setExpandingEntities (true);
410               // out.setPrettyPrinting (true);
411               // out.setXhtml (true);
412
413               setContentHandler (out);
414               setProperty (LEXICAL_HANDLER, out);
415               // save DTD info, if any; why not?
416               setDTDHandler (out);
417               setProperty (DECL_HANDLER, out);
418             }
419           
420         }
421       catch (SAXException e)
422         {
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 ());
428         }
429     }
430   }
431
432   // an interface that adds no value
433   static class LocatorAdapter
434     extends LocatorImpl
435     implements SourceLocator
436   {
437   
438     LocatorAdapter (SAXParseException e)
439     {
440       setSystemId (e.getSystemId ());
441       setPublicId (e.getPublicId ());
442       setLineNumber (e.getLineNumber ());
443       setColumnNumber (e.getColumnNumber ());
444     }
445     
446   }
447
448   // another interface that adds no value
449   static class ListenerAdapter
450     implements ErrorHandler
451   {
452     
453     NullTransformer     transformer;
454     
455     ListenerAdapter (NullTransformer t)
456     {
457       transformer = t;
458     }
459     
460     private TransformerException map (SAXParseException e)
461     {
462       return new TransformerException (
463                                        e.getMessage (),
464                                        new LocatorAdapter (e),
465                                        e);
466     }
467
468     public void error (SAXParseException e)
469       throws SAXParseException
470     {
471       try
472         {
473           if (transformer.errListener != null)
474             transformer.errListener.error (map (e));
475         }
476       catch (TransformerException ex)
477         {
478           transformer.ex = ex;
479           throw e;
480         }
481     }
482
483     public void fatalError (SAXParseException e)
484       throws SAXParseException
485     {
486       try
487         {
488           if (transformer.errListener != null)
489             transformer.errListener.fatalError (map (e));
490           else
491             throw map (e);
492         } catch (TransformerException ex) {
493           transformer.ex = ex;
494           throw e;
495         }
496     }
497
498     public void warning (SAXParseException e)
499       throws SAXParseException
500     {
501       try
502         {
503           if (transformer.errListener != null)
504             transformer.errListener.warning (map (e));
505         }
506       catch (TransformerException ex)
507         {
508           transformer.ex = ex;
509           throw e;
510         }
511     }
512   }
513
514   static class NullTransformer
515     extends Transformer
516   {
517   
518     private URIResolver         uriResolver;
519     private Properties          props = new Properties ();
520     private Hashtable           params = new Hashtable (7);
521     
522     ErrorListener                       errListener = null;
523     TransformerException                ex = null;
524     NullHandler                 handler;
525     
526     NullTransformer ()
527     {
528       super ();
529       handler = new NullHandler (this);
530     }
531     
532     public ErrorListener getErrorListener ()
533     {
534       return errListener;
535     }
536     
537     public void setErrorListener (ErrorListener e)
538     {
539       errListener = e;
540     }
541     
542     public URIResolver getURIResolver ()
543     {
544       return uriResolver;
545     }
546     
547     public void setURIResolver (URIResolver u)
548     {
549       uriResolver = u;
550     }
551
552     public void setOutputProperties (Properties p)
553     {
554       props = (Properties) p.clone ();
555     }
556     
557     public Properties getOutputProperties ()
558     {
559       return (Properties) props.clone ();
560     }
561
562     public void setOutputProperty (String name, String value)
563     {
564       props.setProperty (name, value);
565     }
566     
567     public String getOutputProperty (String name)
568     {
569       return props.getProperty (name);
570     }
571
572     public void clearParameters ()
573     {
574       params.clear ();
575     }
576     
577     public void setParameter (String name, Object value)
578     {
579       props.put (name, value);
580     }
581     
582     public Object getParameter (String name)
583     {
584       return props.get (name);
585     }
586
587     public void transform (Source in, Result out)
588       throws TransformerException
589     {
590       try
591         {
592           XMLReader             producer;
593           InputSource           input;
594           
595           // Input from DOM?
596           if (in instanceof DOMSource)
597             {
598               DOMSource source = (DOMSource) in;
599               
600               if (source.getNode () == null)
601                 throw new IllegalArgumentException ("no DOM node");
602               producer = new DomParser (source.getNode ());
603               input = null;
604               
605               // Input from SAX?
606             }
607           else if (in instanceof SAXSource)
608             {
609               SAXSource source = (SAXSource) in;
610               
611               producer = source.getXMLReader ();
612               if (producer == null)
613                 producer = XMLReaderFactory.createXMLReader ();
614               
615               input = source.getInputSource ();
616               if (input == null)
617                 {
618                   if (source.getSystemId () != null)
619                     input = new InputSource (source.getSystemId ());
620                   else
621                     throw new IllegalArgumentException (
622                                                         "missing SAX input");
623                 }
624               
625               // Input from a stream or something?
626             }
627           else
628             {
629               producer = XMLReaderFactory.createXMLReader ();
630               input = SAXSource.sourceToInputSource (in);
631               if (input == null)
632                 throw new IllegalArgumentException ("missing input");
633             }
634           
635           // preserve original namespace prefixes
636           try
637             {
638               producer.setFeature(handler.FEATURE_URI + "namespace-prefixes",
639                                   true);
640             }
641           catch (Exception e)
642             {
643               /* ignore */
644               // FIXME if we couldn't, "NsFix" stage before the output ..
645             }
646           
647           // arrange the output
648           handler.setResult (out);
649           handler.bind (producer, handler);
650           
651           // then parse ... single element pipeline
652           producer.parse (input);
653           
654         }
655       catch (IOException e)
656         {
657           throw new TransformerException ("transform failed", e);
658           
659         }
660       catch (SAXException e)
661         {
662           if (ex == null && ex.getCause () == e)
663             throw ex;
664           else
665             throw new TransformerException ("transform failed", e);
666           
667         }
668       finally
669         {
670           ex = null;
671         }
672     }
673   }
674
675 }