001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 /*
019 * $Id: TransformerFactoryImpl.java 1225268 2011-12-28 18:41:10Z mrglavas $
020 */
021 package org.apache.xalan.processor;
022
023 import java.io.IOException;
024
025 import javax.xml.XMLConstants;
026 import javax.xml.transform.ErrorListener;
027 import javax.xml.transform.Source;
028 import javax.xml.transform.Templates;
029 import javax.xml.transform.Transformer;
030 import javax.xml.transform.TransformerConfigurationException;
031 import javax.xml.transform.TransformerException;
032 import javax.xml.transform.URIResolver;
033 import javax.xml.transform.dom.DOMResult;
034 import javax.xml.transform.dom.DOMSource;
035 import javax.xml.transform.sax.SAXResult;
036 import javax.xml.transform.sax.SAXSource;
037 import javax.xml.transform.sax.SAXTransformerFactory;
038 import javax.xml.transform.sax.TemplatesHandler;
039 import javax.xml.transform.sax.TransformerHandler;
040 import javax.xml.transform.stream.StreamResult;
041 import javax.xml.transform.stream.StreamSource;
042
043 import org.apache.xalan.res.XSLMessages;
044 import org.apache.xalan.res.XSLTErrorResources;
045 import org.apache.xalan.transformer.TrAXFilter;
046 import org.apache.xalan.transformer.TransformerIdentityImpl;
047 import org.apache.xalan.transformer.TransformerImpl;
048 import org.apache.xalan.transformer.XalanProperties;
049 import org.apache.xml.utils.StopParseException;
050 import org.apache.xml.utils.StylesheetPIHandler;
051 import org.apache.xml.utils.SystemIDResolver;
052 import org.apache.xml.utils.TreeWalker;
053 import org.w3c.dom.Node;
054 import org.xml.sax.InputSource;
055 import org.xml.sax.XMLFilter;
056 import org.xml.sax.XMLReader;
057 import org.xml.sax.helpers.XMLReaderFactory;
058
059 /**
060 * The TransformerFactoryImpl, which implements the TRaX TransformerFactory
061 * interface, processes XSLT stylesheets into a Templates object
062 * (a StylesheetRoot).
063 */
064 public class TransformerFactoryImpl extends SAXTransformerFactory
065 {
066 /**
067 * The path/filename of the property file: XSLTInfo.properties
068 * Maintenance note: see also
069 * <code>org.apache.xpath.functions.FuncSystemProperty.XSLT_PROPERTIES</code>
070 */
071 public static final String XSLT_PROPERTIES =
072 "org/apache/xalan/res/XSLTInfo.properties";
073
074 /**
075 * <p>State of secure processing feature.</p>
076 */
077 private boolean m_isSecureProcessing = false;
078
079 /**
080 * Constructor TransformerFactoryImpl
081 *
082 */
083 public TransformerFactoryImpl()
084 {
085 }
086
087 /** Static string to be used for incremental feature */
088 public static final String FEATURE_INCREMENTAL =
089 "http://xml.apache.org/xalan/features/incremental";
090
091 /** Static string to be used for optimize feature */
092 public static final String FEATURE_OPTIMIZE =
093 "http://xml.apache.org/xalan/features/optimize";
094
095 /** Static string to be used for source_location feature */
096 public static final String FEATURE_SOURCE_LOCATION =
097 XalanProperties.SOURCE_LOCATION;
098
099 public javax.xml.transform.Templates processFromNode(Node node)
100 throws TransformerConfigurationException
101 {
102
103 try
104 {
105 TemplatesHandler builder = newTemplatesHandler();
106 TreeWalker walker = new TreeWalker(builder,
107 new org.apache.xml.utils.DOM2Helper(),
108 builder.getSystemId());
109
110 walker.traverse(node);
111
112 return builder.getTemplates();
113 }
114 catch (org.xml.sax.SAXException se)
115 {
116 if (m_errorListener != null)
117 {
118 try
119 {
120 m_errorListener.fatalError(new TransformerException(se));
121 }
122 catch (TransformerConfigurationException ex)
123 {
124 throw ex;
125 }
126 catch (TransformerException ex)
127 {
128 throw new TransformerConfigurationException(ex);
129 }
130
131 return null;
132 }
133 else
134 {
135
136 // Should remove this later... but right now diagnostics from
137 // TransformerConfigurationException are not good.
138 // se.printStackTrace();
139 throw new TransformerConfigurationException(XSLMessages.createMessage(XSLTErrorResources.ER_PROCESSFROMNODE_FAILED, null), se);
140 //"processFromNode failed", se);
141 }
142 }
143 catch (TransformerConfigurationException tce)
144 {
145 // Assume it's already been reported to the error listener.
146 throw tce;
147 }
148 /* catch (TransformerException tce)
149 {
150 // Assume it's already been reported to the error listener.
151 throw new TransformerConfigurationException(tce.getMessage(), tce);
152 }*/
153 catch (Exception e)
154 {
155 if (m_errorListener != null)
156 {
157 try
158 {
159 m_errorListener.fatalError(new TransformerException(e));
160 }
161 catch (TransformerConfigurationException ex)
162 {
163 throw ex;
164 }
165 catch (TransformerException ex)
166 {
167 throw new TransformerConfigurationException(ex);
168 }
169
170 return null;
171 }
172 else
173 {
174 // Should remove this later... but right now diagnostics from
175 // TransformerConfigurationException are not good.
176 // se.printStackTrace();
177 throw new TransformerConfigurationException(XSLMessages.createMessage(XSLTErrorResources.ER_PROCESSFROMNODE_FAILED, null), e); //"processFromNode failed",
178 //e);
179 }
180 }
181 }
182
183 /**
184 * The systemID that was specified in
185 * processFromNode(Node node, String systemID).
186 */
187 private String m_DOMsystemID = null;
188
189 /**
190 * The systemID that was specified in
191 * processFromNode(Node node, String systemID).
192 *
193 * @return The systemID, or null.
194 */
195 String getDOMsystemID()
196 {
197 return m_DOMsystemID;
198 }
199
200 /**
201 * Process the stylesheet from a DOM tree, if the
202 * processor supports the "http://xml.org/trax/features/dom/input"
203 * feature.
204 *
205 * @param node A DOM tree which must contain
206 * valid transform instructions that this processor understands.
207 * @param systemID The systemID from where xsl:includes and xsl:imports
208 * should be resolved from.
209 *
210 * @return A Templates object capable of being used for transformation purposes.
211 *
212 * @throws TransformerConfigurationException
213 */
214 javax.xml.transform.Templates processFromNode(Node node, String systemID)
215 throws TransformerConfigurationException
216 {
217
218 m_DOMsystemID = systemID;
219
220 return processFromNode(node);
221 }
222
223 /**
224 * Get InputSource specification(s) that are associated with the
225 * given document specified in the source param,
226 * via the xml-stylesheet processing instruction
227 * (see http://www.w3.org/TR/xml-stylesheet/), and that matches
228 * the given criteria. Note that it is possible to return several stylesheets
229 * that match the criteria, in which case they are applied as if they were
230 * a list of imports or cascades.
231 *
232 * <p>Note that DOM2 has it's own mechanism for discovering stylesheets.
233 * Therefore, there isn't a DOM version of this method.</p>
234 *
235 *
236 * @param source The XML source that is to be searched.
237 * @param media The media attribute to be matched. May be null, in which
238 * case the prefered templates will be used (i.e. alternate = no).
239 * @param title The value of the title attribute to match. May be null.
240 * @param charset The value of the charset attribute to match. May be null.
241 *
242 * @return A Source object capable of being used to create a Templates object.
243 *
244 * @throws TransformerConfigurationException
245 */
246 public Source getAssociatedStylesheet(
247 Source source, String media, String title, String charset)
248 throws TransformerConfigurationException
249 {
250
251 String baseID;
252 InputSource isource = null;
253 Node node = null;
254 XMLReader reader = null;
255
256 if (source instanceof DOMSource)
257 {
258 DOMSource dsource = (DOMSource) source;
259
260 node = dsource.getNode();
261 baseID = dsource.getSystemId();
262 }
263 else
264 {
265 isource = SAXSource.sourceToInputSource(source);
266 baseID = isource.getSystemId();
267 }
268
269 // What I try to do here is parse until the first startElement
270 // is found, then throw a special exception in order to terminate
271 // the parse.
272 StylesheetPIHandler handler = new StylesheetPIHandler(baseID, media,
273 title, charset);
274
275 // Use URIResolver. Patch from Dmitri Ilyin
276 if (m_uriResolver != null)
277 {
278 handler.setURIResolver(m_uriResolver);
279 }
280
281 try
282 {
283 if (null != node)
284 {
285 TreeWalker walker = new TreeWalker(handler, new org.apache.xml.utils.DOM2Helper(), baseID);
286
287 walker.traverse(node);
288 }
289 else
290 {
291
292 // Use JAXP1.1 ( if possible )
293 try
294 {
295 javax.xml.parsers.SAXParserFactory factory =
296 javax.xml.parsers.SAXParserFactory.newInstance();
297
298 factory.setNamespaceAware(true);
299
300 if (m_isSecureProcessing)
301 {
302 try
303 {
304 factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
305 }
306 catch (org.xml.sax.SAXException e) {}
307 }
308
309 javax.xml.parsers.SAXParser jaxpParser = factory.newSAXParser();
310
311 reader = jaxpParser.getXMLReader();
312 }
313 catch (javax.xml.parsers.ParserConfigurationException ex)
314 {
315 throw new org.xml.sax.SAXException(ex);
316 }
317 catch (javax.xml.parsers.FactoryConfigurationError ex1)
318 {
319 throw new org.xml.sax.SAXException(ex1.toString());
320 }
321 catch (NoSuchMethodError ex2){}
322 catch (AbstractMethodError ame){}
323
324 if (null == reader)
325 {
326 reader = XMLReaderFactory.createXMLReader();
327 }
328
329 // Need to set options!
330 reader.setContentHandler(handler);
331 reader.parse(isource);
332 }
333 }
334 catch (StopParseException spe)
335 {
336
337 // OK, good.
338 }
339 catch (org.xml.sax.SAXException se)
340 {
341 throw new TransformerConfigurationException(
342 "getAssociatedStylesheets failed", se);
343 }
344 catch (IOException ioe)
345 {
346 throw new TransformerConfigurationException(
347 "getAssociatedStylesheets failed", ioe);
348 }
349
350 return handler.getAssociatedStylesheet();
351 }
352
353 /**
354 * Create a new Transformer object that performs a copy
355 * of the source to the result.
356 *
357 * @return A Transformer object that may be used to perform a transformation
358 * in a single thread, never null.
359 *
360 * @throws TransformerConfigurationException May throw this during
361 * the parse when it is constructing the
362 * Templates object and fails.
363 */
364 public TemplatesHandler newTemplatesHandler()
365 throws TransformerConfigurationException
366 {
367 return new StylesheetHandler(this);
368 }
369
370 /**
371 * <p>Set a feature for this <code>TransformerFactory</code> and <code>Transformer</code>s
372 * or <code>Template</code>s created by this factory.</p>
373 *
374 * <p>
375 * Feature names are fully qualified {@link java.net.URI}s.
376 * Implementations may define their own features.
377 * An {@link TransformerConfigurationException} is thrown if this <code>TransformerFactory</code> or the
378 * <code>Transformer</code>s or <code>Template</code>s it creates cannot support the feature.
379 * It is possible for an <code>TransformerFactory</code> to expose a feature value but be unable to change its state.
380 * </p>
381 *
382 * <p>See {@link javax.xml.transform.TransformerFactory} for full documentation of specific features.</p>
383 *
384 * @param name Feature name.
385 * @param value Is feature state <code>true</code> or <code>false</code>.
386 *
387 * @throws TransformerConfigurationException if this <code>TransformerFactory</code>
388 * or the <code>Transformer</code>s or <code>Template</code>s it creates cannot support this feature.
389 * @throws NullPointerException If the <code>name</code> parameter is null.
390 */
391 public void setFeature(String name, boolean value)
392 throws TransformerConfigurationException {
393
394 // feature name cannot be null
395 if (name == null) {
396 throw new NullPointerException(
397 XSLMessages.createMessage(
398 XSLTErrorResources.ER_SET_FEATURE_NULL_NAME, null));
399 }
400
401 // secure processing?
402 if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) {
403 m_isSecureProcessing = value;
404 }
405 // This implementation does not support the setting of a feature other than
406 // the secure processing feature.
407 else
408 {
409 throw new TransformerConfigurationException(
410 XSLMessages.createMessage(
411 XSLTErrorResources.ER_UNSUPPORTED_FEATURE,
412 new Object[] {name}));
413 }
414 }
415
416 /**
417 * Look up the value of a feature.
418 * <p>The feature name is any fully-qualified URI. It is
419 * possible for an TransformerFactory to recognize a feature name but
420 * to be unable to return its value; this is especially true
421 * in the case of an adapter for a SAX1 Parser, which has
422 * no way of knowing whether the underlying parser is
423 * validating, for example.</p>
424 *
425 * @param name The feature name, which is a fully-qualified URI.
426 * @return The current state of the feature (true or false).
427 */
428 public boolean getFeature(String name) {
429
430 // feature name cannot be null
431 if (name == null)
432 {
433 throw new NullPointerException(
434 XSLMessages.createMessage(
435 XSLTErrorResources.ER_GET_FEATURE_NULL_NAME, null));
436 }
437
438 // Try first with identity comparison, which
439 // will be faster.
440 if ((DOMResult.FEATURE == name) || (DOMSource.FEATURE == name)
441 || (SAXResult.FEATURE == name) || (SAXSource.FEATURE == name)
442 || (StreamResult.FEATURE == name)
443 || (StreamSource.FEATURE == name)
444 || (SAXTransformerFactory.FEATURE == name)
445 || (SAXTransformerFactory.FEATURE_XMLFILTER == name))
446 return true;
447 else if ((DOMResult.FEATURE.equals(name))
448 || (DOMSource.FEATURE.equals(name))
449 || (SAXResult.FEATURE.equals(name))
450 || (SAXSource.FEATURE.equals(name))
451 || (StreamResult.FEATURE.equals(name))
452 || (StreamSource.FEATURE.equals(name))
453 || (SAXTransformerFactory.FEATURE.equals(name))
454 || (SAXTransformerFactory.FEATURE_XMLFILTER.equals(name)))
455 return true;
456 // secure processing?
457 else if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING))
458 return m_isSecureProcessing;
459 else
460 // unknown feature
461 return false;
462 }
463
464 /**
465 * Flag set by FEATURE_OPTIMIZE.
466 * This feature specifies whether to Optimize stylesheet processing. By
467 * default it is set to true.
468 */
469 private boolean m_optimize = true;
470
471 /** Flag set by FEATURE_SOURCE_LOCATION.
472 * This feature specifies whether the transformation phase should
473 * keep track of line and column numbers for the input source
474 * document. Note that this works only when that
475 * information is available from the source -- in other words, if you
476 * pass in a DOM, there's little we can do for you.
477 *
478 * The default is false. Setting it true may significantly
479 * increase storage cost per node.
480 */
481 private boolean m_source_location = false;
482
483 /**
484 * Flag set by FEATURE_INCREMENTAL.
485 * This feature specifies whether to produce output incrementally, rather than
486 * waiting to finish parsing the input before generating any output. By
487 * default this attribute is set to false.
488 */
489 private boolean m_incremental = false;
490
491 /**
492 * Allows the user to set specific attributes on the underlying
493 * implementation.
494 *
495 * @param name The name of the attribute.
496 * @param value The value of the attribute; Boolean or String="true"|"false"
497 *
498 * @throws IllegalArgumentException thrown if the underlying
499 * implementation doesn't recognize the attribute.
500 */
501 public void setAttribute(String name, Object value)
502 throws IllegalArgumentException
503 {
504 if (name.equals(FEATURE_INCREMENTAL))
505 {
506 if(value instanceof Boolean)
507 {
508 // Accept a Boolean object..
509 m_incremental = ((Boolean)value).booleanValue();
510 }
511 else if(value instanceof String)
512 {
513 // .. or a String object
514 m_incremental = (new Boolean((String)value)).booleanValue();
515 }
516 else
517 {
518 // Give a more meaningful error message
519 throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_BAD_VALUE, new Object[]{name, value})); //name + " bad value " + value);
520 }
521 }
522 else if (name.equals(FEATURE_OPTIMIZE))
523 {
524 if(value instanceof Boolean)
525 {
526 // Accept a Boolean object..
527 m_optimize = ((Boolean)value).booleanValue();
528 }
529 else if(value instanceof String)
530 {
531 // .. or a String object
532 m_optimize = (new Boolean((String)value)).booleanValue();
533 }
534 else
535 {
536 // Give a more meaningful error message
537 throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_BAD_VALUE, new Object[]{name, value})); //name + " bad value " + value);
538 }
539 }
540
541 // Custom Xalan feature: annotate DTM with SAX source locator fields.
542 // This gets used during SAX2DTM instantiation.
543 //
544 // %REVIEW% Should the name of this field really be in XalanProperties?
545 // %REVIEW% I hate that it's a global static, but didn't want to change APIs yet.
546 else if(name.equals(FEATURE_SOURCE_LOCATION))
547 {
548 if(value instanceof Boolean)
549 {
550 // Accept a Boolean object..
551 m_source_location = ((Boolean)value).booleanValue();
552 }
553 else if(value instanceof String)
554 {
555 // .. or a String object
556 m_source_location = (new Boolean((String)value)).booleanValue();
557 }
558 else
559 {
560 // Give a more meaningful error message
561 throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_BAD_VALUE, new Object[]{name, value})); //name + " bad value " + value);
562 }
563 }
564
565 else
566 {
567 throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_NOT_SUPPORTED, new Object[]{name})); //name + "not supported");
568 }
569 }
570
571 /**
572 * Allows the user to retrieve specific attributes on the underlying
573 * implementation.
574 *
575 * @param name The name of the attribute.
576 * @return value The value of the attribute.
577 *
578 * @throws IllegalArgumentException thrown if the underlying
579 * implementation doesn't recognize the attribute.
580 */
581 public Object getAttribute(String name) throws IllegalArgumentException
582 {
583 if (name.equals(FEATURE_INCREMENTAL))
584 {
585 return m_incremental ? Boolean.TRUE : Boolean.FALSE;
586 }
587 else if (name.equals(FEATURE_OPTIMIZE))
588 {
589 return m_optimize ? Boolean.TRUE : Boolean.FALSE;
590 }
591 else if (name.equals(FEATURE_SOURCE_LOCATION))
592 {
593 return m_source_location ? Boolean.TRUE : Boolean.FALSE;
594 }
595 else
596 throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_ATTRIB_VALUE_NOT_RECOGNIZED, new Object[]{name})); //name + " attribute not recognized");
597 }
598
599 /**
600 * Create an XMLFilter that uses the given source as the
601 * transformation instructions.
602 *
603 * @param src The source of the transformation instructions.
604 *
605 * @return An XMLFilter object, or null if this feature is not supported.
606 *
607 * @throws TransformerConfigurationException
608 */
609 public XMLFilter newXMLFilter(Source src)
610 throws TransformerConfigurationException
611 {
612
613 Templates templates = newTemplates(src);
614 if( templates==null ) return null;
615
616 return newXMLFilter(templates);
617 }
618
619 /**
620 * Create an XMLFilter that uses the given source as the
621 * transformation instructions.
622 *
623 * @param templates non-null reference to Templates object.
624 *
625 * @return An XMLFilter object, or null if this feature is not supported.
626 *
627 * @throws TransformerConfigurationException
628 */
629 public XMLFilter newXMLFilter(Templates templates)
630 throws TransformerConfigurationException
631 {
632 try
633 {
634 return new TrAXFilter(templates);
635 }
636 catch( TransformerConfigurationException ex )
637 {
638 if( m_errorListener != null)
639 {
640 try
641 {
642 m_errorListener.fatalError( ex );
643 return null;
644 }
645 catch( TransformerConfigurationException ex1 )
646 {
647 throw ex1;
648 }
649 catch( TransformerException ex1 )
650 {
651 throw new TransformerConfigurationException(ex1);
652 }
653 }
654 throw ex;
655 }
656 }
657
658 /**
659 * Get a TransformerHandler object that can process SAX
660 * ContentHandler events into a Result, based on the transformation
661 * instructions specified by the argument.
662 *
663 * @param src The source of the transformation instructions.
664 *
665 * @return TransformerHandler ready to transform SAX events.
666 *
667 * @throws TransformerConfigurationException
668 */
669 public TransformerHandler newTransformerHandler(Source src)
670 throws TransformerConfigurationException
671 {
672
673 Templates templates = newTemplates(src);
674 if( templates==null ) return null;
675
676 return newTransformerHandler(templates);
677 }
678
679 /**
680 * Get a TransformerHandler object that can process SAX
681 * ContentHandler events into a Result, based on the Templates argument.
682 *
683 * @param templates The source of the transformation instructions.
684 *
685 * @return TransformerHandler ready to transform SAX events.
686 * @throws TransformerConfigurationException
687 */
688 public TransformerHandler newTransformerHandler(Templates templates)
689 throws TransformerConfigurationException
690 {
691 try {
692 TransformerImpl transformer =
693 (TransformerImpl) templates.newTransformer();
694 transformer.setURIResolver(m_uriResolver);
695 TransformerHandler th =
696 (TransformerHandler) transformer.getInputContentHandler(true);
697
698 return th;
699 }
700 catch( TransformerConfigurationException ex )
701 {
702 if( m_errorListener != null )
703 {
704 try
705 {
706 m_errorListener.fatalError( ex );
707 return null;
708 }
709 catch (TransformerConfigurationException ex1 )
710 {
711 throw ex1;
712 }
713 catch (TransformerException ex1 )
714 {
715 throw new TransformerConfigurationException(ex1);
716 }
717 }
718
719 throw ex;
720 }
721
722 }
723
724 // /** The identity transform string, for support of newTransformerHandler()
725 // * and newTransformer(). */
726 // private static final String identityTransform =
727 // "<xsl:stylesheet " + "xmlns:xsl='http://www.w3.org/1999/XSL/Transform' "
728 // + "version='1.0'>" + "<xsl:template match='/|node()'>"
729 // + "<xsl:copy-of select='.'/>" + "</xsl:template>" + "</xsl:stylesheet>";
730 //
731 // /** The identity transform Templates, built from identityTransform,
732 // * for support of newTransformerHandler() and newTransformer(). */
733 // private static Templates m_identityTemplate = null;
734
735 /**
736 * Get a TransformerHandler object that can process SAX
737 * ContentHandler events into a Result.
738 *
739 * @return TransformerHandler ready to transform SAX events.
740 *
741 * @throws TransformerConfigurationException
742 */
743 public TransformerHandler newTransformerHandler()
744 throws TransformerConfigurationException
745 {
746 return new TransformerIdentityImpl(m_isSecureProcessing);
747 }
748
749 /**
750 * Process the source into a Transformer object. Care must
751 * be given to know that this object can not be used concurrently
752 * in multiple threads.
753 *
754 * @param source An object that holds a URL, input stream, etc.
755 *
756 * @return A Transformer object capable of
757 * being used for transformation purposes in a single thread.
758 *
759 * @throws TransformerConfigurationException May throw this during the parse when it
760 * is constructing the Templates object and fails.
761 */
762 public Transformer newTransformer(Source source)
763 throws TransformerConfigurationException
764 {
765 try
766 {
767 Templates tmpl=newTemplates( source );
768 /* this can happen if an ErrorListener is present and it doesn't
769 throw any exception in fatalError.
770 The spec says: "a Transformer must use this interface
771 instead of throwing an exception" - the newTemplates() does
772 that, and returns null.
773 */
774 if( tmpl==null ) return null;
775 Transformer transformer = tmpl.newTransformer();
776 transformer.setURIResolver(m_uriResolver);
777 return transformer;
778 }
779 catch( TransformerConfigurationException ex )
780 {
781 if( m_errorListener != null )
782 {
783 try
784 {
785 m_errorListener.fatalError( ex );
786 return null;
787 }
788 catch( TransformerConfigurationException ex1 )
789 {
790 throw ex1;
791 }
792 catch( TransformerException ex1 )
793 {
794 throw new TransformerConfigurationException( ex1 );
795 }
796 }
797 throw ex;
798 }
799 }
800
801 /**
802 * Create a new Transformer object that performs a copy
803 * of the source to the result.
804 *
805 * @return A Transformer object capable of
806 * being used for transformation purposes in a single thread.
807 *
808 * @throws TransformerConfigurationException May throw this during
809 * the parse when it is constructing the
810 * Templates object and it fails.
811 */
812 public Transformer newTransformer() throws TransformerConfigurationException
813 {
814 return new TransformerIdentityImpl(m_isSecureProcessing);
815 }
816
817 /**
818 * Process the source into a Templates object, which is likely
819 * a compiled representation of the source. This Templates object
820 * may then be used concurrently across multiple threads. Creating
821 * a Templates object allows the TransformerFactory to do detailed
822 * performance optimization of transformation instructions, without
823 * penalizing runtime transformation.
824 *
825 * @param source An object that holds a URL, input stream, etc.
826 * @return A Templates object capable of being used for transformation purposes.
827 *
828 * @throws TransformerConfigurationException May throw this during the parse when it
829 * is constructing the Templates object and fails.
830 */
831 public Templates newTemplates(Source source)
832 throws TransformerConfigurationException
833 {
834
835 String baseID = source.getSystemId();
836
837 if (null != baseID) {
838 baseID = SystemIDResolver.getAbsoluteURI(baseID);
839 }
840
841
842 if (source instanceof DOMSource)
843 {
844 DOMSource dsource = (DOMSource) source;
845 Node node = dsource.getNode();
846
847 if (null != node)
848 return processFromNode(node, baseID);
849 else
850 {
851 String messageStr = XSLMessages.createMessage(
852 XSLTErrorResources.ER_ILLEGAL_DOMSOURCE_INPUT, null);
853
854 throw new IllegalArgumentException(messageStr);
855 }
856 }
857
858 TemplatesHandler builder = newTemplatesHandler();
859 builder.setSystemId(baseID);
860
861 try
862 {
863 InputSource isource = SAXSource.sourceToInputSource(source);
864 isource.setSystemId(baseID);
865 XMLReader reader = null;
866
867 if (source instanceof SAXSource)
868 reader = ((SAXSource) source).getXMLReader();
869
870 if (null == reader)
871 {
872
873 // Use JAXP1.1 ( if possible )
874 try
875 {
876 javax.xml.parsers.SAXParserFactory factory =
877 javax.xml.parsers.SAXParserFactory.newInstance();
878
879 factory.setNamespaceAware(true);
880
881 if (m_isSecureProcessing)
882 {
883 try
884 {
885 factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
886 }
887 catch (org.xml.sax.SAXException se) {}
888 }
889
890 javax.xml.parsers.SAXParser jaxpParser = factory.newSAXParser();
891
892 reader = jaxpParser.getXMLReader();
893 }
894 catch (javax.xml.parsers.ParserConfigurationException ex)
895 {
896 throw new org.xml.sax.SAXException(ex);
897 }
898 catch (javax.xml.parsers.FactoryConfigurationError ex1)
899 {
900 throw new org.xml.sax.SAXException(ex1.toString());
901 }
902 catch (NoSuchMethodError ex2){}
903 catch (AbstractMethodError ame){}
904 }
905
906 if (null == reader)
907 reader = XMLReaderFactory.createXMLReader();
908
909 // If you set the namespaces to true, we'll end up getting double
910 // xmlns attributes. Needs to be fixed. -sb
911 // reader.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
912 reader.setContentHandler(builder);
913 reader.parse(isource);
914 }
915 catch (org.xml.sax.SAXException se)
916 {
917 if (m_errorListener != null)
918 {
919 try
920 {
921 m_errorListener.fatalError(new TransformerException(se));
922 }
923 catch (TransformerConfigurationException ex1)
924 {
925 throw ex1;
926 }
927 catch (TransformerException ex1)
928 {
929 throw new TransformerConfigurationException(ex1);
930 }
931 }
932 else
933 {
934 throw new TransformerConfigurationException(se.getMessage(), se);
935 }
936 }
937 catch (Exception e)
938 {
939 if (m_errorListener != null)
940 {
941 try
942 {
943 m_errorListener.fatalError(new TransformerException(e));
944 return null;
945 }
946 catch (TransformerConfigurationException ex1)
947 {
948 throw ex1;
949 }
950 catch (TransformerException ex1)
951 {
952 throw new TransformerConfigurationException(ex1);
953 }
954 }
955 else
956 {
957 throw new TransformerConfigurationException(e.getMessage(), e);
958 }
959 }
960
961 return builder.getTemplates();
962 }
963
964 /**
965 * The object that implements the URIResolver interface,
966 * or null.
967 */
968 URIResolver m_uriResolver;
969
970 /**
971 * Set an object that will be used to resolve URIs used in
972 * xsl:import, etc. This will be used as the default for the
973 * transformation.
974 * @param resolver An object that implements the URIResolver interface,
975 * or null.
976 */
977 public void setURIResolver(URIResolver resolver)
978 {
979 m_uriResolver = resolver;
980 }
981
982 /**
983 * Get the object that will be used to resolve URIs used in
984 * xsl:import, etc. This will be used as the default for the
985 * transformation.
986 *
987 * @return The URIResolver that was set with setURIResolver.
988 */
989 public URIResolver getURIResolver()
990 {
991 return m_uriResolver;
992 }
993
994 /** The error listener. */
995 private ErrorListener m_errorListener = new org.apache.xml.utils.DefaultErrorHandler(false);
996
997 /**
998 * Get the error listener in effect for the TransformerFactory.
999 *
1000 * @return A non-null reference to an error listener.
1001 */
1002 public ErrorListener getErrorListener()
1003 {
1004 return m_errorListener;
1005 }
1006
1007 /**
1008 * Set an error listener for the TransformerFactory.
1009 *
1010 * @param listener Must be a non-null reference to an ErrorListener.
1011 *
1012 * @throws IllegalArgumentException if the listener argument is null.
1013 */
1014 public void setErrorListener(ErrorListener listener)
1015 throws IllegalArgumentException
1016 {
1017
1018 if (null == listener)
1019 throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_ERRORLISTENER, null));
1020 // "ErrorListener");
1021
1022 m_errorListener = listener;
1023 }
1024
1025 /**
1026 * Return the state of the secure processing feature.
1027 *
1028 * @return state of the secure processing feature.
1029 */
1030 public boolean isSecureProcessing()
1031 {
1032 return m_isSecureProcessing;
1033 }
1034 }