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 }