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