KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xalan > xsltc > trax > TransformerImpl


1 /*
2  * Copyright 2001-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: TransformerImpl.java,v 1.80 2004/02/23 21:33:15 igorh Exp $
18  */

19
20 package org.apache.xalan.xsltc.trax;
21
22 import java.io.File JavaDoc;
23 import java.io.FileOutputStream JavaDoc;
24 import java.io.IOException JavaDoc;
25 import java.io.InputStream JavaDoc;
26 import java.io.OutputStream JavaDoc;
27 import java.io.Reader JavaDoc;
28 import java.io.Writer JavaDoc;
29 import java.net.URL JavaDoc;
30 import java.net.URLConnection JavaDoc;
31 import java.net.UnknownServiceException JavaDoc;
32 import java.util.Enumeration JavaDoc;
33 import java.util.Properties JavaDoc;
34 import java.util.StringTokenizer JavaDoc;
35 import java.util.Vector JavaDoc;
36
37 import javax.xml.parsers.DocumentBuilder JavaDoc;
38 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
39 import javax.xml.parsers.ParserConfigurationException JavaDoc;
40 import javax.xml.transform.ErrorListener JavaDoc;
41 import javax.xml.transform.OutputKeys JavaDoc;
42 import javax.xml.transform.Result JavaDoc;
43 import javax.xml.transform.Source JavaDoc;
44 import javax.xml.transform.Transformer JavaDoc;
45 import javax.xml.transform.TransformerException JavaDoc;
46 import javax.xml.transform.URIResolver JavaDoc;
47 import javax.xml.transform.dom.DOMResult JavaDoc;
48 import javax.xml.transform.dom.DOMSource JavaDoc;
49 import javax.xml.transform.sax.SAXResult JavaDoc;
50 import javax.xml.transform.sax.SAXSource JavaDoc;
51 import javax.xml.transform.stream.StreamResult JavaDoc;
52 import javax.xml.transform.stream.StreamSource JavaDoc;
53
54 import org.apache.xml.utils.SystemIDResolver;
55
56 import org.apache.xalan.xsltc.DOM;
57 import org.apache.xalan.xsltc.DOMCache;
58 import org.apache.xalan.xsltc.DOMEnhancedForDTM;
59 import org.apache.xalan.xsltc.StripFilter;
60 import org.apache.xalan.xsltc.Translet;
61 import org.apache.xalan.xsltc.TransletException;
62 import org.apache.xml.serializer.OutputPropertiesFactory;
63 import org.apache.xml.serializer.SerializationHandler;
64 import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
65 import org.apache.xalan.xsltc.dom.DOMWSFilter;
66 import org.apache.xalan.xsltc.dom.SAXImpl;
67 import org.apache.xalan.xsltc.dom.XSLTCDTMManager;
68 import org.apache.xalan.xsltc.runtime.AbstractTranslet;
69 import org.apache.xalan.xsltc.runtime.Hashtable;
70 import org.apache.xalan.xsltc.runtime.output.TransletOutputHandlerFactory;
71
72 import org.apache.xml.dtm.DTMWSFilter;
73 import org.apache.xml.utils.XMLReaderManager;
74
75 import org.xml.sax.ContentHandler JavaDoc;
76 import org.xml.sax.InputSource JavaDoc;
77 import org.xml.sax.SAXException JavaDoc;
78 import org.xml.sax.XMLReader JavaDoc;
79 import org.xml.sax.ext.LexicalHandler JavaDoc;
80
81 /**
82  * @author Morten Jorgensen
83  * @author G. Todd Miller
84  * @author Santiago Pericas-Geertsen
85  */

86 public final class TransformerImpl extends Transformer JavaDoc
87     implements DOMCache, ErrorListener JavaDoc
88 {
89     private final static String JavaDoc EMPTY_STRING = "";
90     private final static String JavaDoc NO_STRING = "no";
91     private final static String JavaDoc YES_STRING = "yes";
92     private final static String JavaDoc XML_STRING = "xml";
93
94     private final static String JavaDoc LEXICAL_HANDLER_PROPERTY =
95     "http://xml.org/sax/properties/lexical-handler";
96     private static final String JavaDoc NAMESPACE_FEATURE =
97     "http://xml.org/sax/features/namespaces";
98     
99     /**
100      * A reference to the translet or null if the identity transform.
101      */

102     private AbstractTranslet _translet = null;
103
104     /**
105      * The output method of this transformation.
106      */

107     private String JavaDoc _method = null;
108
109     /**
110      * The output encoding of this transformation.
111      */

112     private String JavaDoc _encoding = null;
113
114     /**
115      * The systemId set in input source.
116      */

117     private String JavaDoc _sourceSystemId = null;
118
119     /**
120      * An error listener for runtime errors.
121      */

122     private ErrorListener JavaDoc _errorListener = this;
123
124     /**
125      * A reference to a URI resolver for calls to document().
126      */

127     private URIResolver JavaDoc _uriResolver = null;
128
129     /**
130      * Output properties of this transformer instance.
131      */

132     private Properties JavaDoc _properties, _propertiesClone;
133
134     /**
135      * A reference to an output handler factory.
136      */

137     private TransletOutputHandlerFactory _tohFactory = null;
138
139     /**
140      * A reference to a internal DOM represenation of the input.
141      */

142     private DOM _dom = null;
143
144     /**
145      * Number of indent spaces to add when indentation is on.
146      */

147     private int _indentNumber;
148
149     /**
150      * A reference to the transformer factory that this templates
151      * object belongs to.
152      */

153     private TransformerFactoryImpl _tfactory = null;
154
155     /**
156      * A reference to the XSLTCDTMManager which is used to build the DOM/DTM
157      * for this transformer.
158      */

159     private XSLTCDTMManager _dtmManager = null;
160
161     /**
162      * A reference to an object that creates and caches XMLReader objects.
163      */

164     private XMLReaderManager _readerManager = XMLReaderManager.getInstance();
165     
166     /**
167      * A flag indicating whether we use incremental building of the DTM.
168      */

169     //private boolean _isIncremental = false;
170

171     /**
172      * A flag indicating whether this transformer implements the identity
173      * transform.
174      */

175     private boolean _isIdentity = false;
176
177     /**
178      * A hashtable to store parameters for the identity transform. These
179      * are not needed during the transformation, but we must keep track of
180      * them to be fully complaint with the JAXP API.
181      */

182     private Hashtable _parameters = null;
183
184     /**
185      * This class wraps an ErrorListener into a MessageHandler in order to
186      * capture messages reported via xsl:message.
187      */

188     static class MessageHandler
189            extends org.apache.xalan.xsltc.runtime.MessageHandler
190     {
191     private ErrorListener JavaDoc _errorListener;
192      
193     public MessageHandler(ErrorListener JavaDoc errorListener) {
194         _errorListener = errorListener;
195     }
196      
197     public void displayMessage(String JavaDoc msg) {
198         if(_errorListener == null) {
199         System.err.println(msg);
200         }
201         else {
202         try {
203             _errorListener.warning(new TransformerException JavaDoc(msg));
204         }
205         catch (TransformerException JavaDoc e) {
206             // ignored
207
}
208         }
209     }
210     }
211
212     protected TransformerImpl(Properties JavaDoc outputProperties, int indentNumber,
213     TransformerFactoryImpl tfactory)
214     {
215     this(null, outputProperties, indentNumber, tfactory);
216     _isIdentity = true;
217     // _properties.put(OutputKeys.METHOD, "xml");
218
}
219
220     protected TransformerImpl(Translet translet, Properties JavaDoc outputProperties,
221     int indentNumber, TransformerFactoryImpl tfactory)
222     {
223     _translet = (AbstractTranslet) translet;
224     _properties = createOutputProperties(outputProperties);
225     _propertiesClone = (Properties JavaDoc) _properties.clone();
226     _indentNumber = indentNumber;
227     _tfactory = tfactory;
228     //_isIncremental = tfactory._incremental;
229
}
230
231     /**
232      * Returns the translet wrapped inside this Transformer or
233      * null if this is the identity transform.
234      */

235     protected AbstractTranslet getTranslet() {
236     return _translet;
237     }
238
239     public boolean isIdentity() {
240     return _isIdentity;
241     }
242
243     /**
244      * Implements JAXP's Transformer.transform()
245      *
246      * @param source Contains the input XML document
247      * @param result Will contain the output from the transformation
248      * @throws TransformerException
249      */

250     public void transform(Source JavaDoc source, Result JavaDoc result)
251     throws TransformerException JavaDoc
252     {
253     if (!_isIdentity) {
254         if (_translet == null) {
255         ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_TRANSLET_ERR);
256         throw new TransformerException JavaDoc(err.toString());
257         }
258         // Pass output properties to the translet
259
transferOutputProperties(_translet);
260     }
261         
262     final SerializationHandler toHandler = getOutputHandler(result);
263     if (toHandler == null) {
264         ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_HANDLER_ERR);
265         throw new TransformerException JavaDoc(err.toString());
266     }
267
268     if (_uriResolver != null && !_isIdentity) {
269         _translet.setDOMCache(this);
270     }
271
272     // Pass output properties to handler if identity
273
if (_isIdentity) {
274         transferOutputProperties(toHandler);
275     }
276
277     transform(source, toHandler, _encoding);
278
279     if (result instanceof DOMResult JavaDoc) {
280         ((DOMResult JavaDoc)result).setNode(_tohFactory.getNode());
281     }
282     }
283
284     /**
285      * Create an output handler for the transformation output based on
286      * the type and contents of the TrAX Result object passed to the
287      * transform() method.
288      */

289     public SerializationHandler getOutputHandler(Result JavaDoc result)
290     throws TransformerException JavaDoc
291     {
292     // Get output method using get() to ignore defaults
293
_method = (String JavaDoc) _properties.get(OutputKeys.METHOD);
294
295     // Get encoding using getProperty() to use defaults
296
_encoding = (String JavaDoc) _properties.getProperty(OutputKeys.ENCODING);
297
298     _tohFactory = TransletOutputHandlerFactory.newInstance();
299     _tohFactory.setEncoding(_encoding);
300     if (_method != null) {
301         _tohFactory.setOutputMethod(_method);
302     }
303
304     // Set indentation number in the factory
305
if (_indentNumber >= 0) {
306         _tohFactory.setIndentNumber(_indentNumber);
307     }
308
309     // Return the content handler for this Result object
310
try {
311         // Result object could be SAXResult, DOMResult, or StreamResult
312
if (result instanceof SAXResult JavaDoc) {
313                 final SAXResult JavaDoc target = (SAXResult JavaDoc)result;
314                 final ContentHandler JavaDoc handler = target.getHandler();
315
316         _tohFactory.setHandler(handler);
317
318                 /**
319                  * Fix for bug 24414
320                  * If the lexicalHandler is set then we need to get that
321                  * for obtaining the lexical information
322                  */

323                 LexicalHandler JavaDoc lexicalHandler = target.getLexicalHandler();
324
325                 if (lexicalHandler != null ) {
326             _tohFactory.setLexicalHandler(lexicalHandler);
327         }
328
329         _tohFactory.setOutputType(TransletOutputHandlerFactory.SAX);
330         return _tohFactory.getSerializationHandler();
331             }
332         else if (result instanceof DOMResult JavaDoc) {
333         _tohFactory.setNode(((DOMResult JavaDoc) result).getNode());
334         _tohFactory.setOutputType(TransletOutputHandlerFactory.DOM);
335         return _tohFactory.getSerializationHandler();
336             }
337         else if (result instanceof StreamResult JavaDoc) {
338         // Get StreamResult
339
final StreamResult JavaDoc target = (StreamResult JavaDoc) result;
340
341         // StreamResult may have been created with a java.io.File,
342
// java.io.Writer, java.io.OutputStream or just a String
343
// systemId.
344

345         _tohFactory.setOutputType(TransletOutputHandlerFactory.STREAM);
346
347         // try to get a Writer from Result object
348
final Writer JavaDoc writer = target.getWriter();
349         if (writer != null) {
350             _tohFactory.setWriter(writer);
351             return _tohFactory.getSerializationHandler();
352         }
353
354         // or try to get an OutputStream from Result object
355
final OutputStream JavaDoc ostream = target.getOutputStream();
356         if (ostream != null) {
357             _tohFactory.setOutputStream(ostream);
358             return _tohFactory.getSerializationHandler();
359         }
360
361         // or try to get just a systemId string from Result object
362
String JavaDoc systemId = result.getSystemId();
363         if (systemId == null) {
364             ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_RESULT_ERR);
365                     throw new TransformerException JavaDoc(err.toString());
366         }
367
368         // System Id may be in one of several forms, (1) a uri
369
// that starts with 'file:', (2) uri that starts with 'http:'
370
// or (3) just a filename on the local system.
371
URL JavaDoc url = null;
372         if (systemId.startsWith("file:")) {
373                     url = new URL JavaDoc(systemId);
374             _tohFactory.setOutputStream(
375                 new FileOutputStream JavaDoc(url.getFile()));
376             return _tohFactory.getSerializationHandler();
377                 }
378                 else if (systemId.startsWith("http:")) {
379                     url = new URL JavaDoc(systemId);
380                     final URLConnection JavaDoc connection = url.openConnection();
381             _tohFactory.setOutputStream(connection.getOutputStream());
382             return _tohFactory.getSerializationHandler();
383                 }
384                 else {
385                     // system id is just a filename
386
url = new File JavaDoc(systemId).toURL();
387             _tohFactory.setOutputStream(
388                 new FileOutputStream JavaDoc(url.getFile()));
389             return _tohFactory.getSerializationHandler();
390                 }
391         }
392     }
393         // If we cannot write to the location specified by the SystemId
394
catch (UnknownServiceException JavaDoc e) {
395             throw new TransformerException JavaDoc(e);
396         }
397         catch (ParserConfigurationException JavaDoc e) {
398             throw new TransformerException JavaDoc(e);
399         }
400         // If we cannot create the file specified by the SystemId
401
catch (IOException JavaDoc e) {
402             throw new TransformerException JavaDoc(e);
403         }
404     return null;
405     }
406
407     /**
408      * Set the internal DOM that will be used for the next transformation
409      */

410     protected void setDOM(DOM dom) {
411     _dom = dom;
412     }
413
414     /**
415      * Builds an internal DOM from a TrAX Source object
416      */

417     private DOM getDOM(Source JavaDoc source) throws TransformerException JavaDoc {
418         try {
419             DOM dom = null;
420
421             if (source != null) {
422                 DTMWSFilter wsfilter;
423                 if (_translet != null && _translet instanceof StripFilter) {
424                     wsfilter = new DOMWSFilter(_translet);
425                  } else {
426                     wsfilter = null;
427                  }
428             
429                  boolean hasIdCall = (_translet != null) ? _translet.hasIdCall()
430                                                          : false;
431
432                  if (_dtmManager == null) {
433                      _dtmManager =
434                          (XSLTCDTMManager)_tfactory.getDTMManagerClass()
435                                                    .newInstance();
436                  }
437                  dom = (DOM)_dtmManager.getDTM(source, false, wsfilter, true,
438                                               false, false, 0, hasIdCall);
439             } else if (_dom != null) {
440                  dom = _dom;
441                  _dom = null; // use only once, so reset to 'null'
442
} else {
443                  return null;
444             }
445
446             if (!_isIdentity) {
447                 // Give the translet the opportunity to make a prepass of
448
// the document, in case it can extract useful information early
449
_translet.prepassDocument(dom);
450             }
451
452             return dom;
453
454         }
455         catch (Exception JavaDoc e) {
456             if (_errorListener != null) {
457                 postErrorToListener(e.getMessage());
458             }
459             throw new TransformerException JavaDoc(e);
460         }
461     }
462  
463     /**
464      * Returns the {@link org.apache.xalan.xsltc.trax.TransformerFactoryImpl}
465      * object that create this <code>Transformer</code>.
466      */

467     protected TransformerFactoryImpl getTransformerFactory() {
468         return _tfactory;
469     }
470
471     private void transformIdentity(Source JavaDoc source, SerializationHandler handler)
472     throws Exception JavaDoc
473     {
474         // Get systemId from source
475
if (source != null) {
476             _sourceSystemId = source.getSystemId();
477         }
478
479         if (source instanceof StreamSource JavaDoc) {
480             final StreamSource JavaDoc stream = (StreamSource JavaDoc) source;
481             final InputStream JavaDoc streamInput = stream.getInputStream();
482             final Reader JavaDoc streamReader = stream.getReader();
483             final XMLReader JavaDoc reader = _readerManager.getXMLReader();
484
485             try {
486                 // Hook up reader and output handler
487
try {
488                     reader.setProperty(LEXICAL_HANDLER_PROPERTY, handler);
489                 }
490                 catch (SAXException JavaDoc e) {
491                     // Falls through
492
}
493                 reader.setContentHandler(handler);
494
495                 // Create input source from source
496
InputSource JavaDoc input;
497                 if (streamInput != null) {
498                     input = new InputSource JavaDoc(streamInput);
499                     input.setSystemId(_sourceSystemId);
500                 }
501                 else if (streamReader != null) {
502                     input = new InputSource JavaDoc(streamReader);
503                     input.setSystemId(_sourceSystemId);
504                 }
505                 else if (_sourceSystemId != null) {
506                     input = new InputSource JavaDoc(_sourceSystemId);
507                 }
508                 else {
509                     ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_SOURCE_ERR);
510                     throw new TransformerException JavaDoc(err.toString());
511                 }
512
513                 // Start pushing SAX events
514
reader.parse(input);
515             } finally {
516                 _readerManager.releaseXMLReader(reader);
517             }
518         } else if (source instanceof SAXSource JavaDoc) {
519             final SAXSource JavaDoc sax = (SAXSource JavaDoc) source;
520             XMLReader JavaDoc reader = sax.getXMLReader();
521             final InputSource JavaDoc input = sax.getInputSource();
522             boolean userReader = true;
523
524             try {
525                 // Create a reader if not set by user
526
if (reader == null) {
527                     reader = _readerManager.getXMLReader();
528                     userReader = false;
529                 }
530
531                 // Hook up reader and output handler
532
try {
533                     reader.setProperty(LEXICAL_HANDLER_PROPERTY, handler);
534                 }
535                 catch (SAXException JavaDoc e) {
536                     // Falls through
537
}
538                 reader.setContentHandler(handler);
539
540                 // Start pushing SAX events
541
reader.parse(input);
542             } finally {
543                 if (!userReader) {
544                     _readerManager.releaseXMLReader(reader);
545                 }
546             }
547         } else if (source instanceof DOMSource JavaDoc) {
548             final DOMSource JavaDoc domsrc = (DOMSource JavaDoc) source;
549             new DOM2TO(domsrc.getNode(), handler).parse();
550         } else if (source instanceof XSLTCSource) {
551             final DOM dom = ((XSLTCSource) source).getDOM(null, _translet);
552             ((SAXImpl)dom).copy(handler);
553         } else {
554             ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_SOURCE_ERR);
555             throw new TransformerException JavaDoc(err.toString());
556         }
557     }
558
559     /**
560      * Internal transformation method - uses the internal APIs of XSLTC
561      */

562     private void transform(Source JavaDoc source, SerializationHandler handler,
563     String JavaDoc encoding) throws TransformerException JavaDoc
564     {
565     try {
566             /*
567              * According to JAXP1.2, new SAXSource()/StreamSource()
568              * should create an empty input tree, with a default root node.
569              * new DOMSource()creates an empty document using DocumentBuilder.
570              * newDocument(); Use DocumentBuilder.newDocument() for all 3
571              * situations, since there is no clear spec. how to create
572              * an empty tree when both SAXSource() and StreamSource() are used.
573              */

574             if ((source instanceof StreamSource JavaDoc && source.getSystemId()==null
575                 && ((StreamSource JavaDoc)source).getInputStream()==null &&
576                 ((StreamSource JavaDoc)source).getReader()==null)||
577                 (source instanceof SAXSource JavaDoc &&
578                 ((SAXSource JavaDoc)source).getInputSource()==null &&
579                 ((SAXSource JavaDoc)source).getXMLReader()==null )||
580                 (source instanceof DOMSource JavaDoc &&
581                 ((DOMSource JavaDoc)source).getNode()==null)){
582                         DocumentBuilderFactory JavaDoc builderF =
583                                 DocumentBuilderFactory.newInstance();
584                         DocumentBuilder JavaDoc builder =
585                                 builderF.newDocumentBuilder();
586                         String JavaDoc systemID = source.getSystemId();
587                         source = new DOMSource JavaDoc(builder.newDocument());
588
589                         // Copy system ID from original, empty Source to new
590
if (systemID != null) {
591                           source.setSystemId(systemID);
592                         }
593             }
594         if (_isIdentity) {
595         transformIdentity(source, handler);
596         } else {
597         _translet.transform(getDOM(source), handler);
598         }
599     } catch (TransletException e) {
600         if (_errorListener != null) postErrorToListener(e.getMessage());
601         throw new TransformerException JavaDoc(e);
602     } catch (RuntimeException JavaDoc e) {
603         if (_errorListener != null) postErrorToListener(e.getMessage());
604         throw new TransformerException JavaDoc(e);
605     } catch (Exception JavaDoc e) {
606         if (_errorListener != null) postErrorToListener(e.getMessage());
607         throw new TransformerException JavaDoc(e);
608     } finally {
609             _dtmManager = null;
610         }
611     }
612
613     /**
614      * Implements JAXP's Transformer.getErrorListener()
615      * Get the error event handler in effect for the transformation.
616      *
617      * @return The error event handler currently in effect
618      */

619     public ErrorListener JavaDoc getErrorListener() {
620     return _errorListener;
621     }
622
623     /**
624      * Implements JAXP's Transformer.setErrorListener()
625      * Set the error event listener in effect for the transformation.
626      * Register a message handler in the translet in order to forward
627      * xsl:messages to error listener.
628      *
629      * @param listener The error event listener to use
630      * @throws IllegalArgumentException
631      */

632     public void setErrorListener(ErrorListener JavaDoc listener)
633     throws IllegalArgumentException JavaDoc {
634         if (listener == null) {
635         ErrorMsg err = new ErrorMsg(ErrorMsg.ERROR_LISTENER_NULL_ERR,
636                     "Transformer");
637             throw new IllegalArgumentException JavaDoc(err.toString());
638     }
639         _errorListener = listener;
640         
641     // Register a message handler to report xsl:messages
642
if (_translet != null)
643         _translet.setMessageHandler(new MessageHandler(_errorListener));
644     }
645
646     /**
647      * Inform TrAX error listener of an error
648      */

649     private void postErrorToListener(String JavaDoc message) {
650         try {
651             _errorListener.error(new TransformerException JavaDoc(message));
652     }
653     catch (TransformerException JavaDoc e) {
654             // ignored - transformation cannot be continued
655
}
656     }
657
658     /**
659      * Inform TrAX error listener of a warning
660      */

661     private void postWarningToListener(String JavaDoc message) {
662         try {
663             _errorListener.warning(new TransformerException JavaDoc(message));
664         }
665     catch (TransformerException JavaDoc e) {
666             // ignored - transformation cannot be continued
667
}
668     }
669
670     /**
671      * The translet stores all CDATA sections set in the <xsl:output> element
672      * in a Hashtable. This method will re-construct the whitespace separated
673      * list of elements given in the <xsl:output> element.
674      */

675     private String JavaDoc makeCDATAString(Hashtable cdata) {
676     // Return a 'null' string if no CDATA section elements were specified
677
if (cdata == null) return null;
678
679     StringBuffer JavaDoc result = new StringBuffer JavaDoc();
680
681     // Get an enumeration of all the elements in the hashtable
682
Enumeration JavaDoc elements = cdata.keys();
683     if (elements.hasMoreElements()) {
684         result.append((String JavaDoc)elements.nextElement());
685         while (elements.hasMoreElements()) {
686         String JavaDoc element = (String JavaDoc)elements.nextElement();
687         result.append(' ');
688         result.append(element);
689         }
690     }
691     
692     return(result.toString());
693     }
694
695     /**
696      * Implements JAXP's Transformer.getOutputProperties().
697      * Returns a copy of the output properties for the transformation. This is
698      * a set of layered properties. The first layer contains properties set by
699      * calls to setOutputProperty() and setOutputProperties() on this class,
700      * and the output settings defined in the stylesheet's <xsl:output>
701      * element makes up the second level, while the default XSLT output
702      * settings are returned on the third level.
703      *
704      * @return Properties in effect for this Transformer
705      */

706     public Properties JavaDoc getOutputProperties() {
707     return (Properties JavaDoc) _properties.clone();
708     }
709
710     /**
711      * Implements JAXP's Transformer.getOutputProperty().
712      * Get an output property that is in effect for the transformation. The
713      * property specified may be a property that was set with setOutputProperty,
714      * or it may be a property specified in the stylesheet.
715      *
716      * @param name A non-null string that contains the name of the property
717      * @throws IllegalArgumentException if the property name is not known
718      */

719     public String JavaDoc getOutputProperty(String JavaDoc name)
720     throws IllegalArgumentException JavaDoc
721     {
722     if (!validOutputProperty(name)) {
723         ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_UNKNOWN_PROP_ERR, name);
724         throw new IllegalArgumentException JavaDoc(err.toString());
725     }
726     return _properties.getProperty(name);
727     }
728
729     /**
730      * Implements JAXP's Transformer.setOutputProperties().
731      * Set the output properties for the transformation. These properties
732      * will override properties set in the Templates with xsl:output.
733      * Unrecognised properties will be quitely ignored.
734      *
735      * @param properties The properties to use for the Transformer
736      * @throws IllegalArgumentException Never, errors are ignored
737      */

738     public void setOutputProperties(Properties JavaDoc properties)
739     throws IllegalArgumentException JavaDoc
740     {
741     if (properties != null) {
742         final Enumeration JavaDoc names = properties.propertyNames();
743
744         while (names.hasMoreElements()) {
745         final String JavaDoc name = (String JavaDoc) names.nextElement();
746
747         // Ignore lower layer properties
748
if (isDefaultProperty(name, properties)) continue;
749
750         if (validOutputProperty(name)) {
751             _properties.setProperty(name, properties.getProperty(name));
752         }
753         else {
754             ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_UNKNOWN_PROP_ERR, name);
755             throw new IllegalArgumentException JavaDoc(err.toString());
756         }
757         }
758     }
759     else {
760         _properties = _propertiesClone;
761     }
762     }
763
764     /**
765      * Implements JAXP's Transformer.setOutputProperty().
766      * Get an output property that is in effect for the transformation. The
767      * property specified may be a property that was set with
768      * setOutputProperty(), or it may be a property specified in the stylesheet.
769      *
770      * @param name The name of the property to set
771      * @param value The value to assign to the property
772      * @throws IllegalArgumentException Never, errors are ignored
773      */

774     public void setOutputProperty(String JavaDoc name, String JavaDoc value)
775     throws IllegalArgumentException JavaDoc
776     {
777     if (!validOutputProperty(name)) {
778         ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_UNKNOWN_PROP_ERR, name);
779         throw new IllegalArgumentException JavaDoc(err.toString());
780     }
781     _properties.setProperty(name, value);
782     }
783
784     /**
785      * Internal method to pass any properties to the translet prior to
786      * initiating the transformation
787      */

788     private void transferOutputProperties(AbstractTranslet translet)
789     {
790     // Return right now if no properties are set
791
if (_properties == null) return;
792
793     // Get a list of all the defined properties
794
Enumeration JavaDoc names = _properties.propertyNames();
795     while (names.hasMoreElements()) {
796         // Note the use of get() instead of getProperty()
797
String JavaDoc name = (String JavaDoc) names.nextElement();
798         String JavaDoc value = (String JavaDoc) _properties.get(name);
799
800         // Ignore default properties
801
if (value == null) continue;
802
803         // Pass property value to translet - override previous setting
804
if (name.equals(OutputKeys.ENCODING)) {
805         translet._encoding = value;
806         }
807         else if (name.equals(OutputKeys.METHOD)) {
808         translet._method = value;
809         }
810         else if (name.equals(OutputKeys.DOCTYPE_PUBLIC)) {
811         translet._doctypePublic = value;
812         }
813         else if (name.equals(OutputKeys.DOCTYPE_SYSTEM)) {
814         translet._doctypeSystem = value;
815         }
816         else if (name.equals(OutputKeys.MEDIA_TYPE)) {
817         translet._mediaType = value;
818         }
819         else if (name.equals(OutputKeys.STANDALONE)) {
820         translet._standalone = value;
821         }
822         else if (name.equals(OutputKeys.VERSION)) {
823         translet._version = value;
824         }
825         else if (name.equals(OutputKeys.OMIT_XML_DECLARATION)) {
826         translet._omitHeader =
827             (value != null && value.toLowerCase().equals("yes"));
828         }
829         else if (name.equals(OutputKeys.INDENT)) {
830         translet._indent =
831             (value != null && value.toLowerCase().equals("yes"));
832         }
833         else if (name.equals(OutputKeys.CDATA_SECTION_ELEMENTS)) {
834         if (value != null) {
835             translet._cdata = null; // clear previous setting
836
StringTokenizer JavaDoc e = new StringTokenizer JavaDoc(value);
837             while (e.hasMoreTokens()) {
838             translet.addCdataElement(e.nextToken());
839             }
840         }
841         }
842     }
843     }
844
845     /**
846      * This method is used to pass any properties to the output handler
847      * when running the identity transform.
848      */

849     public void transferOutputProperties(SerializationHandler handler)
850     {
851     // Return right now if no properties are set
852
if (_properties == null) return;
853
854     String JavaDoc doctypePublic = null;
855     String JavaDoc doctypeSystem = null;
856
857     // Get a list of all the defined properties
858
Enumeration JavaDoc names = _properties.propertyNames();
859     while (names.hasMoreElements()) {
860         // Note the use of get() instead of getProperty()
861
String JavaDoc name = (String JavaDoc) names.nextElement();
862         String JavaDoc value = (String JavaDoc) _properties.get(name);
863
864         // Ignore default properties
865
if (value == null) continue;
866
867         // Pass property value to translet - override previous setting
868
if (name.equals(OutputKeys.DOCTYPE_PUBLIC)) {
869         doctypePublic = value;
870         }
871         else if (name.equals(OutputKeys.DOCTYPE_SYSTEM)) {
872         doctypeSystem = value;
873         }
874         else if (name.equals(OutputKeys.MEDIA_TYPE)) {
875         handler.setMediaType(value);
876         }
877         else if (name.equals(OutputKeys.STANDALONE)) {
878         handler.setStandalone(value);
879         }
880         else if (name.equals(OutputKeys.VERSION)) {
881         handler.setVersion(value);
882         }
883         else if (name.equals(OutputKeys.OMIT_XML_DECLARATION)) {
884         handler.setOmitXMLDeclaration(
885             value != null && value.toLowerCase().equals("yes"));
886         }
887         else if (name.equals(OutputKeys.INDENT)) {
888         handler.setIndent(
889             value != null && value.toLowerCase().equals("yes"));
890         }
891         else if (name.equals(OutputKeys.CDATA_SECTION_ELEMENTS)) {
892         if (value != null) {
893             StringTokenizer JavaDoc e = new StringTokenizer JavaDoc(value);
894                     Vector JavaDoc uriAndLocalNames = null;
895             while (e.hasMoreTokens()) {
896             final String JavaDoc token = e.nextToken();
897
898                         // look for the last colon, as the String may be
899
// something like "http://abc.com:local"
900
int lastcolon = token.lastIndexOf(':');
901                         String JavaDoc uri;
902                         String JavaDoc localName;
903                         if (lastcolon > 0) {
904                             uri = token.substring(0, lastcolon);
905                             localName = token.substring(lastcolon+1);
906                         } else {
907                             // no colon at all, lets hope this is the
908
// local name itself then
909
uri = null;
910                             localName = token;
911                         }
912
913                         if (uriAndLocalNames == null) {
914                             uriAndLocalNames = new Vector JavaDoc();
915                         }
916                         // add the uri/localName as a pair, in that order
917
uriAndLocalNames.addElement(uri);
918                         uriAndLocalNames.addElement(localName);
919                     }
920                     handler.setCdataSectionElements(uriAndLocalNames);
921         }
922         }
923     }
924
925     // Call setDoctype() if needed
926
if (doctypePublic != null || doctypeSystem != null) {
927         handler.setDoctype(doctypeSystem, doctypePublic);
928     }
929     }
930
931     /**
932      * Internal method to create the initial set of properties. There
933      * are two layers of properties: the default layer and the base layer.
934      * The latter contains properties defined in the stylesheet or by
935      * the user using this API.
936      */

937     private Properties JavaDoc createOutputProperties(Properties JavaDoc outputProperties) {
938     final Properties JavaDoc defaults = new Properties JavaDoc();
939     setDefaults(defaults, "xml");
940
941     // Copy propeties set in stylesheet to base
942
final Properties JavaDoc base = new Properties JavaDoc(defaults);
943     if (outputProperties != null) {
944         final Enumeration JavaDoc names = outputProperties.propertyNames();
945         while (names.hasMoreElements()) {
946         final String JavaDoc name = (String JavaDoc) names.nextElement();
947         base.setProperty(name, outputProperties.getProperty(name));
948         }
949     }
950     else {
951         base.setProperty(OutputKeys.ENCODING, _translet._encoding);
952         if (_translet._method != null)
953             base.setProperty(OutputKeys.METHOD, _translet._method);
954     }
955
956     // Update defaults based on output method
957
final String JavaDoc method = base.getProperty(OutputKeys.METHOD);
958     if (method != null) {
959         if (method.equals("html")) {
960             setDefaults(defaults,"html");
961         }
962         else if (method.equals("text")) {
963             setDefaults(defaults,"text");
964         }
965     }
966
967     return base;
968     }
969
970     /**
971      * Internal method to get the default properties from the
972      * serializer factory and set them on the property object.
973      * @param props a java.util.Property object on which the properties are set.
974      * @param method The output method type, one of "xml", "text", "html" ...
975      */

976     private void setDefaults(Properties JavaDoc props, String JavaDoc method)
977     {
978         final Properties JavaDoc method_props =
979             OutputPropertiesFactory.getDefaultMethodProperties(method);
980         {
981             final Enumeration JavaDoc names = method_props.propertyNames();
982             while (names.hasMoreElements())
983             {
984                 final String JavaDoc name = (String JavaDoc)names.nextElement();
985                 props.setProperty(name, method_props.getProperty(name));
986             }
987         }
988     }
989     /**
990      * Verifies if a given output property name is a property defined in
991      * the JAXP 1.1 / TrAX spec
992      */

993     private boolean validOutputProperty(String JavaDoc name) {
994     return (name.equals(OutputKeys.ENCODING) ||
995         name.equals(OutputKeys.METHOD) ||
996         name.equals(OutputKeys.INDENT) ||
997         name.equals(OutputKeys.DOCTYPE_PUBLIC) ||
998         name.equals(OutputKeys.DOCTYPE_SYSTEM) ||
999         name.equals(OutputKeys.CDATA_SECTION_ELEMENTS) ||
1000        name.equals(OutputKeys.MEDIA_TYPE) ||
1001        name.equals(OutputKeys.OMIT_XML_DECLARATION) ||
1002        name.equals(OutputKeys.STANDALONE) ||
1003        name.equals(OutputKeys.VERSION) ||
1004        name.charAt(0) == '{');
1005    }
1006
1007    /**
1008     * Checks if a given output property is default (2nd layer only)
1009     */

1010    private boolean isDefaultProperty(String JavaDoc name, Properties JavaDoc properties) {
1011    return (properties.get(name) == null);
1012    }
1013
1014    /**
1015     * Implements JAXP's Transformer.setParameter()
1016     * Add a parameter for the transformation. The parameter is simply passed
1017     * on to the translet - no validation is performed - so any unused
1018     * parameters are quitely ignored by the translet.
1019     *
1020     * @param name The name of the parameter
1021     * @param value The value to assign to the parameter
1022     */

1023    public void setParameter(String JavaDoc name, Object JavaDoc value) {
1024        
1025        if (value == null) {
1026            ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_INVALID_SET_PARAM_VALUE, name);
1027            throw new IllegalArgumentException JavaDoc(err.toString());
1028        }
1029             
1030    if (_isIdentity) {
1031        if (_parameters == null) {
1032        _parameters = new Hashtable();
1033        }
1034        _parameters.put(name, value);
1035    }
1036    else {
1037        _translet.addParameter(name, value);
1038    }
1039    }
1040
1041    /**
1042     * Implements JAXP's Transformer.clearParameters()
1043     * Clear all parameters set with setParameter. Clears the translet's
1044     * parameter stack.
1045     */

1046    public void clearParameters() {
1047    if (_isIdentity && _parameters != null) {
1048        _parameters.clear();
1049    }
1050    else {
1051        _translet.clearParameters();
1052    }
1053    }
1054
1055    /**
1056     * Implements JAXP's Transformer.getParameter()
1057     * Returns the value of a given parameter. Note that the translet will not
1058     * keep values for parameters that were not defined in the stylesheet.
1059     *
1060     * @param name The name of the parameter
1061     * @return An object that contains the value assigned to the parameter
1062     */

1063    public final Object JavaDoc getParameter(String JavaDoc name) {
1064    if (_isIdentity) {
1065        return (_parameters != null) ? _parameters.get(name) : null;
1066    }
1067    else {
1068        return _translet.getParameter(name);
1069    }
1070    }
1071
1072    /**
1073     * Implements JAXP's Transformer.getURIResolver()
1074     * Set the object currently used to resolve URIs used in document().
1075     *
1076     * @return The URLResolver object currently in use
1077     */

1078    public URIResolver JavaDoc getURIResolver() {
1079    return _uriResolver;
1080    }
1081
1082    /**
1083     * Implements JAXP's Transformer.setURIResolver()
1084     * Set an object that will be used to resolve URIs used in document().
1085     *
1086     * @param resolver The URIResolver to use in document()
1087     */

1088    public void setURIResolver(URIResolver JavaDoc resolver) {
1089    _uriResolver = resolver;
1090    }
1091
1092    /**
1093     * This class should only be used as a DOMCache for the translet if the
1094     * URIResolver has been set.
1095     *
1096     * The method implements XSLTC's DOMCache interface, which is used to
1097     * plug in an external document loader into a translet. This method acts
1098     * as an adapter between TrAX's URIResolver interface and XSLTC's
1099     * DOMCache interface. This approach is simple, but removes the
1100     * possibility of using external document caches with XSLTC.
1101     *
1102     * @param baseURI The base URI used by the document call.
1103     * @param href The href argument passed to the document function.
1104     * @param translet A reference to the translet requesting the document
1105     */

1106    public DOM retrieveDocument(String JavaDoc baseURI, String JavaDoc href, Translet translet) {
1107    try {
1108            // Argument to document function was: document('');
1109
if (href.length() == 0) {
1110                href = new String JavaDoc(baseURI);
1111            }
1112
1113            /*
1114             * Fix for bug 24188
1115             * Incase the _uriResolver.resolve(href,base) is null
1116             * try to still retrieve the document before returning null
1117             * and throwing the FileNotFoundException in
1118             * org.apache.xalan.xsltc.dom.LoadDocument
1119             *
1120             */

1121            Source JavaDoc resolvedSource = _uriResolver.resolve(href, baseURI);
1122            if (resolvedSource == null) {
1123                StreamSource JavaDoc streamSource = new StreamSource JavaDoc(
1124                     SystemIDResolver.getAbsoluteURI(href, baseURI));
1125                return getDOM(streamSource) ;
1126            }
1127
1128            return getDOM(resolvedSource);
1129    }
1130    catch (TransformerException JavaDoc e) {
1131        if (_errorListener != null)
1132        postErrorToListener("File not found: " + e.getMessage());
1133        return(null);
1134    }
1135    }
1136
1137    /**
1138     * Receive notification of a recoverable error.
1139     * The transformer must continue to provide normal parsing events after
1140     * invoking this method. It should still be possible for the application
1141     * to process the document through to the end.
1142     *
1143     * @param exception The warning information encapsulated in a transformer
1144     * exception.
1145     * @throws TransformerException if the application chooses to discontinue
1146     * the transformation (always does in our case).
1147     */

1148    public void error(TransformerException JavaDoc e)
1149    throws TransformerException JavaDoc
1150    {
1151        Throwable JavaDoc wrapped = e.getException();
1152        if (wrapped != null) {
1153            System.err.println(new ErrorMsg(ErrorMsg.ERROR_PLUS_WRAPPED_MSG,
1154                                            e.getMessageAndLocation(),
1155                                            wrapped.getMessage()));
1156        } else {
1157            System.err.println(new ErrorMsg(ErrorMsg.ERROR_MSG,
1158                                            e.getMessageAndLocation()));
1159        }
1160        throw e;
1161    }
1162
1163    /**
1164     * Receive notification of a non-recoverable error.
1165     * The application must assume that the transformation cannot continue
1166     * after the Transformer has invoked this method, and should continue
1167     * (if at all) only to collect addition error messages. In fact,
1168     * Transformers are free to stop reporting events once this method has
1169     * been invoked.
1170     *
1171     * @param exception The warning information encapsulated in a transformer
1172     * exception.
1173     * @throws TransformerException if the application chooses to discontinue
1174     * the transformation (always does in our case).
1175     */

1176    public void fatalError(TransformerException JavaDoc e)
1177    throws TransformerException JavaDoc
1178    {
1179        Throwable JavaDoc wrapped = e.getException();
1180        if (wrapped != null) {
1181            System.err.println(new ErrorMsg(ErrorMsg.FATAL_ERR_PLUS_WRAPPED_MSG,
1182                                            e.getMessageAndLocation(),
1183                                            wrapped.getMessage()));
1184        } else {
1185            System.err.println(new ErrorMsg(ErrorMsg.FATAL_ERR_MSG,
1186                                            e.getMessageAndLocation()));
1187        }
1188        throw e;
1189    }
1190
1191    /**
1192     * Receive notification of a warning.
1193     * Transformers can use this method to report conditions that are not
1194     * errors or fatal errors. The default behaviour is to take no action.
1195     * After invoking this method, the Transformer must continue with the
1196     * transformation. It should still be possible for the application to
1197     * process the document through to the end.
1198     *
1199     * @param exception The warning information encapsulated in a transformer
1200     * exception.
1201     * @throws TransformerException if the application chooses to discontinue
1202     * the transformation (never does in our case).
1203     */

1204    public void warning(TransformerException JavaDoc e)
1205    throws TransformerException JavaDoc
1206    {
1207        Throwable JavaDoc wrapped = e.getException();
1208        if (wrapped != null) {
1209            System.err.println(new ErrorMsg(ErrorMsg.WARNING_PLUS_WRAPPED_MSG,
1210                                            e.getMessageAndLocation(),
1211                                            wrapped.getMessage()));
1212        } else {
1213            System.err.println(new ErrorMsg(ErrorMsg.WARNING_MSG,
1214                                            e.getMessageAndLocation()));
1215        }
1216    }
1217
1218}
1219
Popular Tags