1 /* 2 * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. 3 */ 4 /* 5 * Licensed to the Apache Software Foundation (ASF) under one or more 6 * contributor license agreements. See the NOTICE file distributed with 7 * this work for additional information regarding copyright ownership. 8 * The ASF licenses this file to You under the Apache License, Version 2.0 9 * (the "License"); you may not use this file except in compliance with 10 * the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 */ 20 /* 21 * $Id: TransformerImpl.java,v 1.10 2007/06/13 01:57:09 joehw Exp $ 22 */ 23 24 package com.sun.org.apache.xalan.internal.xsltc.trax; 25 26 import com.sun.org.apache.xalan.internal.XalanConstants; 27 import com.sun.org.apache.xalan.internal.utils.FactoryImpl; 28 import com.sun.org.apache.xalan.internal.utils.XMLSecurityManager; 29 import com.sun.org.apache.xalan.internal.xsltc.DOM; 30 import com.sun.org.apache.xalan.internal.xsltc.DOMCache; 31 import com.sun.org.apache.xalan.internal.xsltc.StripFilter; 32 import com.sun.org.apache.xalan.internal.xsltc.Translet; 33 import com.sun.org.apache.xalan.internal.xsltc.TransletException; 34 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg; 35 import com.sun.org.apache.xalan.internal.xsltc.dom.DOMWSFilter; 36 import com.sun.org.apache.xalan.internal.xsltc.dom.SAXImpl; 37 import com.sun.org.apache.xalan.internal.xsltc.dom.XSLTCDTMManager; 38 import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; 39 import com.sun.org.apache.xalan.internal.xsltc.runtime.output.TransletOutputHandlerFactory; 40 import com.sun.org.apache.xml.internal.dtm.DTMWSFilter; 41 import com.sun.org.apache.xml.internal.serializer.OutputPropertiesFactory; 42 import com.sun.org.apache.xml.internal.serializer.SerializationHandler; 43 import com.sun.org.apache.xml.internal.utils.SystemIDResolver; 44 import com.sun.org.apache.xml.internal.utils.XMLReaderManager; 45 import java.io.File; 46 import java.io.FileOutputStream; 47 import java.io.IOException; 48 import java.io.InputStream; 49 import java.io.OutputStream; 50 import java.io.Reader; 51 import java.io.Writer; 52 import java.net.URI; 53 import java.net.URL; 54 import java.net.URLConnection; 55 import java.net.UnknownServiceException; 56 import java.util.ArrayList; 57 import java.util.Enumeration; 58 import java.util.HashMap; 59 import java.util.Map; 60 import java.util.Properties; 61 import java.util.StringTokenizer; 62 import javax.xml.XMLConstants; 63 import javax.xml.catalog.CatalogFeatures; 64 import javax.xml.catalog.CatalogManager; 65 import javax.xml.catalog.CatalogUriResolver; 66 import javax.xml.parsers.DocumentBuilder; 67 import javax.xml.parsers.DocumentBuilderFactory; 68 import javax.xml.parsers.ParserConfigurationException; 69 import javax.xml.stream.XMLEventReader; 70 import javax.xml.stream.XMLStreamReader; 71 import javax.xml.transform.ErrorListener; 72 import javax.xml.transform.OutputKeys; 73 import javax.xml.transform.Result; 74 import javax.xml.transform.Source; 75 import javax.xml.transform.Transformer; 76 import javax.xml.transform.TransformerException; 77 import javax.xml.transform.URIResolver; 78 import javax.xml.transform.dom.DOMResult; 79 import javax.xml.transform.dom.DOMSource; 80 import javax.xml.transform.sax.SAXResult; 81 import javax.xml.transform.sax.SAXSource; 82 import javax.xml.transform.stax.StAXResult; 83 import javax.xml.transform.stax.StAXSource; 84 import javax.xml.transform.stream.StreamResult; 85 import javax.xml.transform.stream.StreamSource; 86 import jdk.xml.internal.JdkXmlFeatures; 87 import jdk.xml.internal.JdkXmlUtils; 88 import org.xml.sax.ContentHandler; 89 import org.xml.sax.InputSource; 90 import org.xml.sax.SAXException; 91 import org.xml.sax.XMLReader; 92 import org.xml.sax.ext.LexicalHandler; 93 94 /** 95 * @author Morten Jorgensen 96 * @author G. Todd Miller 97 * @author Santiago Pericas-Geertsen 98 */ 99 public final class TransformerImpl extends Transformer 100 implements DOMCache, ErrorListener 101 { 102 103 private final static String LEXICAL_HANDLER_PROPERTY = 104 "http://xml.org/sax/properties/lexical-handler"; 105 private static final String NAMESPACE_FEATURE = 106 "http://xml.org/sax/features/namespaces"; 107 108 /** 109 * Namespace prefixes feature for {@link XMLReader}. 110 */ 111 private static final String NAMESPACE_PREFIXES_FEATURE = 112 "http://xml.org/sax/features/namespace-prefixes"; 113 114 /** 115 * A reference to the translet or null if the identity transform. 116 */ 117 private AbstractTranslet _translet = null; 118 119 /** 120 * The output method of this transformation. 121 */ 122 private String _method = null; 123 124 /** 125 * The output encoding of this transformation. 126 */ 127 private String _encoding = null; 128 129 /** 130 * The systemId set in input source. 131 */ 132 private String _sourceSystemId = null; 133 134 /** 135 * An error listener for runtime errors. 136 */ 137 private ErrorListener _errorListener = this; 138 139 /** 140 * A reference to a URI resolver for calls to document(). 141 */ 142 private URIResolver _uriResolver = null; 143 144 /** 145 * Output properties of this transformer instance. 146 */ 147 private Properties _properties, _propertiesClone; 148 149 /** 150 * A reference to an output handler factory. 151 */ 152 private TransletOutputHandlerFactory _tohFactory = null; 153 154 /** 155 * A reference to a internal DOM representation of the input. 156 */ 157 private DOM _dom = null; 158 159 /** 160 * Number of indent spaces to add when indentation is on. 161 */ 162 private int _indentNumber; 163 164 /** 165 * A reference to the transformer factory that this templates 166 * object belongs to. 167 */ 168 private TransformerFactoryImpl _tfactory = null; 169 170 /** 171 * A reference to the output stream, if we create one in our code. 172 */ 173 private OutputStream _ostream = null; 174 175 /** 176 * A reference to the XSLTCDTMManager which is used to build the DOM/DTM 177 * for this transformer. 178 */ 179 private XSLTCDTMManager _dtmManager = null; 180 181 /** 182 * A reference to an object that creates and caches XMLReader objects. 183 */ 184 private XMLReaderManager _readerManager; 185 186 /** 187 * A flag indicating whether we use incremental building of the DTM. 188 */ 189 //private boolean _isIncremental = false; 190 191 /** 192 * A flag indicating whether this transformer implements the identity 193 * transform. 194 */ 195 private boolean _isIdentity = false; 196 197 /** 198 * State of the secure processing feature. 199 */ 200 private boolean _isSecureProcessing = false; 201 202 /** 203 * Indicates whether implementation parts should use 204 * service loader (or similar). 205 * Note the default value (false) is the safe option.. 206 */ 207 private boolean _useServicesMechanism; 208 /** 209 * protocols allowed for external references set by the stylesheet processing instruction, Import and Include element. 210 */ 211 private String _accessExternalStylesheet = XalanConstants.EXTERNAL_ACCESS_DEFAULT; 212 /** 213 * protocols allowed for external DTD references in source file and/or stylesheet. 214 */ 215 private String _accessExternalDTD = XalanConstants.EXTERNAL_ACCESS_DEFAULT; 216 217 private XMLSecurityManager _securityManager; 218 /** 219 * A map to store parameters for the identity transform. These 220 * are not needed during the transformation, but we must keep track of 221 * them to be fully complaint with the JAXP API. 222 */ 223 private Map<String, Object> _parameters = null; 224 225 // Catalog features 226 CatalogFeatures _catalogFeatures; 227 CatalogUriResolver _catalogUriResolver; 228 229 // Catalog is enabled by default 230 boolean _useCatalog = true; 231 232 233 /** 234 * This class wraps an ErrorListener into a MessageHandler in order to 235 * capture messages reported via xsl:message. 236 */ 237 static class MessageHandler 238 extends com.sun.org.apache.xalan.internal.xsltc.runtime.MessageHandler 239 { 240 private ErrorListener _errorListener; 241 242 public MessageHandler(ErrorListener errorListener) { 243 _errorListener = errorListener; 244 } 245 246 @Override 247 public void displayMessage(String msg) { 248 if(_errorListener == null) { 249 System.err.println(msg); 250 } 251 else { 252 try { 253 _errorListener.warning(new TransformerException(msg)); 254 } 255 catch (TransformerException e) { 256 // ignored 257 } 258 } 259 } 260 } 261 262 protected TransformerImpl(Properties outputProperties, int indentNumber, 263 TransformerFactoryImpl tfactory) 264 { 265 this(null, outputProperties, indentNumber, tfactory); 266 _isIdentity = true; 267 // _properties.put(OutputKeys.METHOD, "xml"); 268 } 269 270 protected TransformerImpl(Translet translet, Properties outputProperties, 271 int indentNumber, TransformerFactoryImpl tfactory) 272 { 273 _translet = (AbstractTranslet) translet; 274 _properties = createOutputProperties(outputProperties); 275 _propertiesClone = (Properties) _properties.clone(); 276 _indentNumber = indentNumber; 277 _tfactory = tfactory; 278 _useServicesMechanism = _tfactory.useServicesMechnism(); 279 _accessExternalStylesheet = (String)_tfactory.getAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET); 280 _accessExternalDTD = (String)_tfactory.getAttribute(XMLConstants.ACCESS_EXTERNAL_DTD); 281 _securityManager = (XMLSecurityManager)_tfactory.getAttribute(XalanConstants.SECURITY_MANAGER); 282 _readerManager = XMLReaderManager.getInstance(_useServicesMechanism); 283 _readerManager.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, _accessExternalDTD); 284 _readerManager.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, _isSecureProcessing); 285 _readerManager.setProperty(XalanConstants.SECURITY_MANAGER, _securityManager); 286 287 _useCatalog = _tfactory.getFeature(XMLConstants.USE_CATALOG); 288 if (_useCatalog) { 289 _catalogFeatures = (CatalogFeatures)_tfactory.getAttribute(JdkXmlFeatures.CATALOG_FEATURES); 290 String catalogFiles = _catalogFeatures.get(CatalogFeatures.Feature.DEFER); 291 if (catalogFiles != null) { 292 _readerManager.setFeature(XMLConstants.USE_CATALOG, _useCatalog); 293 _readerManager.setProperty(JdkXmlFeatures.CATALOG_FEATURES, _catalogFeatures); 294 } 295 } 296 //_isIncremental = tfactory._incremental; 297 } 298 299 /** 300 * Return the state of the secure processing feature. 301 */ 302 public boolean isSecureProcessing() { 303 return _isSecureProcessing; 304 } 305 306 /** 307 * Set the state of the secure processing feature. 308 */ 309 public void setSecureProcessing(boolean flag) { 310 _isSecureProcessing = flag; 311 _readerManager.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, _isSecureProcessing); 312 } 313 /** 314 * Return the state of the services mechanism feature. 315 */ 316 public boolean useServicesMechnism() { 317 return _useServicesMechanism; 318 } 319 320 /** 321 * Set the state of the services mechanism feature. 322 */ 323 public void setServicesMechnism(boolean flag) { 324 _useServicesMechanism = flag; 325 } 326 327 /** 328 * Returns the translet wrapped inside this Transformer or 329 * null if this is the identity transform. 330 */ 331 protected AbstractTranslet getTranslet() { 332 return _translet; 333 } 334 335 public boolean isIdentity() { 336 return _isIdentity; 337 } 338 339 /** 340 * Implements JAXP's Transformer.transform() 341 * 342 * @param source Contains the input XML document 343 * @param result Will contain the output from the transformation 344 * @throws TransformerException 345 */ 346 @Override 347 public void transform(Source source, Result result) 348 throws TransformerException 349 { 350 if (!_isIdentity) { 351 if (_translet == null) { 352 ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_TRANSLET_ERR); 353 throw new TransformerException(err.toString()); 354 } 355 // Pass output properties to the translet 356 transferOutputProperties(_translet); 357 } 358 359 final SerializationHandler toHandler = getOutputHandler(result); 360 if (toHandler == null) { 361 ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_HANDLER_ERR); 362 throw new TransformerException(err.toString()); 363 } 364 365 if (!_isIdentity && (_uriResolver != null || (_tfactory.getFeature(XMLConstants.USE_CATALOG) 366 && _tfactory.getAttribute(JdkXmlUtils.CATALOG_FILES) != null))) { 367 _translet.setDOMCache(this); 368 } 369 370 // Pass output properties to handler if identity 371 if (_isIdentity) { 372 transferOutputProperties(toHandler); 373 } 374 375 transform(source, toHandler, _encoding); 376 try{ 377 if (result instanceof DOMResult) { 378 ((DOMResult)result).setNode(_tohFactory.getNode()); 379 } else if (result instanceof StAXResult) { 380 if (((StAXResult) result).getXMLEventWriter() != null) 381 { 382 (_tohFactory.getXMLEventWriter()).flush(); 383 } 384 else if (((StAXResult) result).getXMLStreamWriter() != null) { 385 (_tohFactory.getXMLStreamWriter()).flush(); 386 //result = new StAXResult(_tohFactory.getXMLStreamWriter()); 387 } 388 } 389 } catch (Exception e) { 390 System.out.println("Result writing error"); 391 } 392 } 393 394 /** 395 * Create an output handler for the transformation output based on 396 * the type and contents of the TrAX Result object passed to the 397 * transform() method. 398 */ 399 public SerializationHandler getOutputHandler(Result result) 400 throws TransformerException 401 { 402 // Get output method using get() to ignore defaults 403 _method = (String) _properties.get(OutputKeys.METHOD); 404 405 // Get encoding using getProperty() to use defaults 406 _encoding = (String) _properties.getProperty(OutputKeys.ENCODING); 407 408 _tohFactory = TransletOutputHandlerFactory.newInstance(_useServicesMechanism); 409 _tohFactory.setEncoding(_encoding); 410 if (_method != null) { 411 _tohFactory.setOutputMethod(_method); 412 } 413 414 // Set indentation number in the factory 415 if (_indentNumber >= 0) { 416 _tohFactory.setIndentNumber(_indentNumber); 417 } 418 419 // Return the content handler for this Result object 420 try { 421 // Result object could be SAXResult, DOMResult, or StreamResult 422 if (result instanceof SAXResult) { 423 final SAXResult target = (SAXResult)result; 424 final ContentHandler handler = target.getHandler(); 425 426 _tohFactory.setHandler(handler); 427 428 /** 429 * Fix for bug 24414 430 * If the lexicalHandler is set then we need to get that 431 * for obtaining the lexical information 432 */ 433 LexicalHandler lexicalHandler = target.getLexicalHandler(); 434 435 if (lexicalHandler != null ) { 436 _tohFactory.setLexicalHandler(lexicalHandler); 437 } 438 439 _tohFactory.setOutputType(TransletOutputHandlerFactory.SAX); 440 return _tohFactory.getSerializationHandler(); 441 } 442 else if (result instanceof StAXResult) { 443 if (((StAXResult) result).getXMLEventWriter() != null) 444 _tohFactory.setXMLEventWriter(((StAXResult) result).getXMLEventWriter()); 445 else if (((StAXResult) result).getXMLStreamWriter() != null) 446 _tohFactory.setXMLStreamWriter(((StAXResult) result).getXMLStreamWriter()); 447 _tohFactory.setOutputType(TransletOutputHandlerFactory.STAX); 448 return _tohFactory.getSerializationHandler(); 449 } 450 else if (result instanceof DOMResult) { 451 _tohFactory.setNode(((DOMResult) result).getNode()); 452 _tohFactory.setNextSibling(((DOMResult) result).getNextSibling()); 453 _tohFactory.setOutputType(TransletOutputHandlerFactory.DOM); 454 return _tohFactory.getSerializationHandler(); 455 } 456 else if (result instanceof StreamResult) { 457 // Get StreamResult 458 final StreamResult target = (StreamResult) result; 459 460 // StreamResult may have been created with a java.io.File, 461 // java.io.Writer, java.io.OutputStream or just a String 462 // systemId. 463 464 _tohFactory.setOutputType(TransletOutputHandlerFactory.STREAM); 465 466 // try to get a Writer from Result object 467 final Writer writer = target.getWriter(); 468 if (writer != null) { 469 _tohFactory.setWriter(writer); 470 return _tohFactory.getSerializationHandler(); 471 } 472 473 // or try to get an OutputStream from Result object 474 final OutputStream ostream = target.getOutputStream(); 475 if (ostream != null) { 476 _tohFactory.setOutputStream(ostream); 477 return _tohFactory.getSerializationHandler(); 478 } 479 480 // or try to get just a systemId string from Result object 481 String systemId = result.getSystemId(); 482 if (systemId == null) { 483 ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_RESULT_ERR); 484 throw new TransformerException(err.toString()); 485 } 486 487 // System Id may be in one of several forms, (1) a uri 488 // that starts with 'file:', (2) uri that starts with 'http:' 489 // or (3) just a filename on the local system. 490 URL url; 491 if (systemId.startsWith("file:")) { 492 // if StreamResult(File) or setSystemID(File) was used, 493 // the systemId will be URI encoded as a result of File.toURI(), 494 // it must be decoded for use by URL 495 try{ 496 URI uri = new URI(systemId) ; 497 systemId = "file:"; 498 499 String host = uri.getHost(); // decoded String 500 String path = uri.getPath(); //decoded String 501 if (path == null) { 502 path = ""; 503 } 504 505 // if host (URI authority) then file:// + host + path 506 // else just path (may be absolute or relative) 507 if (host != null) { 508 systemId += "//" + host + path; 509 } else { 510 systemId += "//" + path; 511 } 512 } 513 catch (Exception exception) { 514 // URI exception which means nothing can be done so OK to ignore 515 } 516 517 url = new URL(systemId); 518 _ostream = new FileOutputStream(url.getFile()); 519 _tohFactory.setOutputStream(_ostream); 520 return _tohFactory.getSerializationHandler(); 521 } 522 else if (systemId.startsWith("http:")) { 523 url = new URL(systemId); 524 final URLConnection connection = url.openConnection(); 525 _tohFactory.setOutputStream(_ostream = connection.getOutputStream()); 526 return _tohFactory.getSerializationHandler(); 527 } 528 else { 529 // system id is just a filename 530 _tohFactory.setOutputStream( 531 _ostream = new FileOutputStream(new File(systemId))); 532 return _tohFactory.getSerializationHandler(); 533 } 534 } 535 } 536 // If we cannot write to the location specified by the SystemId 537 catch (UnknownServiceException e) { 538 throw new TransformerException(e); 539 } 540 catch (ParserConfigurationException e) { 541 throw new TransformerException(e); 542 } 543 // If we cannot create the file specified by the SystemId 544 catch (IOException e) { 545 throw new TransformerException(e); 546 } 547 return null; 548 } 549 550 /** 551 * Set the internal DOM that will be used for the next transformation 552 */ 553 protected void setDOM(DOM dom) { 554 _dom = dom; 555 } 556 557 /** 558 * Builds an internal DOM from a TrAX Source object 559 */ 560 private DOM getDOM(Source source) throws TransformerException { 561 try { 562 DOM dom; 563 564 if (source != null) { 565 DTMWSFilter wsfilter; 566 if (_translet != null && _translet instanceof StripFilter) { 567 wsfilter = new DOMWSFilter(_translet); 568 } else { 569 wsfilter = null; 570 } 571 572 boolean hasIdCall = (_translet != null) ? _translet.hasIdCall() 573 : false; 574 575 if (_dtmManager == null) { 576 _dtmManager = 577 _tfactory.createNewDTMManagerInstance(); 578 _dtmManager.setServicesMechnism(_useServicesMechanism); 579 } 580 dom = (DOM)_dtmManager.getDTM(source, false, wsfilter, true, 581 false, false, 0, hasIdCall); 582 } else if (_dom != null) { 583 dom = _dom; 584 _dom = null; // use only once, so reset to 'null' 585 } else { 586 return null; 587 } 588 589 if (!_isIdentity) { 590 // Give the translet the opportunity to make a prepass of 591 // the document, in case it can extract useful information early 592 _translet.prepassDocument(dom); 593 } 594 595 return dom; 596 597 } 598 catch (Exception e) { 599 if (_errorListener != null) { 600 postErrorToListener(e.getMessage()); 601 } 602 throw new TransformerException(e); 603 } 604 } 605 606 /** 607 * Returns the {@link com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl} 608 * object that create this <code>Transformer</code>. 609 */ 610 protected TransformerFactoryImpl getTransformerFactory() { 611 return _tfactory; 612 } 613 614 /** 615 * Returns the {@link com.sun.org.apache.xalan.internal.xsltc.runtime.output.TransletOutputHandlerFactory} 616 * object that create the <code>TransletOutputHandler</code>. 617 */ 618 protected TransletOutputHandlerFactory getTransletOutputHandlerFactory() { 619 return _tohFactory; 620 } 621 622 private void transformIdentity(Source source, SerializationHandler handler) 623 throws Exception 624 { 625 // Get systemId from source 626 if (source != null) { 627 _sourceSystemId = source.getSystemId(); 628 } 629 630 if (source instanceof StreamSource) { 631 final StreamSource stream = (StreamSource) source; 632 final InputStream streamInput = stream.getInputStream(); 633 final Reader streamReader = stream.getReader(); 634 final XMLReader reader = _readerManager.getXMLReader(); 635 636 try { 637 // Hook up reader and output handler 638 try { 639 reader.setProperty(LEXICAL_HANDLER_PROPERTY, handler); 640 reader.setFeature(NAMESPACE_PREFIXES_FEATURE, true); 641 } catch (SAXException e) { 642 // Falls through 643 } 644 reader.setContentHandler(handler); 645 646 // Create input source from source 647 InputSource input; 648 if (streamInput != null) { 649 input = new InputSource(streamInput); 650 input.setSystemId(_sourceSystemId); 651 } 652 else if (streamReader != null) { 653 input = new InputSource(streamReader); 654 input.setSystemId(_sourceSystemId); 655 } 656 else if (_sourceSystemId != null) { 657 input = new InputSource(_sourceSystemId); 658 } 659 else { 660 ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_SOURCE_ERR); 661 throw new TransformerException(err.toString()); 662 } 663 664 // Start pushing SAX events 665 reader.parse(input); 666 } finally { 667 _readerManager.releaseXMLReader(reader); 668 } 669 } else if (source instanceof SAXSource) { 670 final SAXSource sax = (SAXSource) source; 671 XMLReader reader = sax.getXMLReader(); 672 final InputSource input = sax.getInputSource(); 673 boolean userReader = true; 674 675 try { 676 // Create a reader if not set by user 677 if (reader == null) { 678 reader = _readerManager.getXMLReader(); 679 userReader = false; 680 } 681 682 // Hook up reader and output handler 683 try { 684 reader.setProperty(LEXICAL_HANDLER_PROPERTY, handler); 685 reader.setFeature(NAMESPACE_PREFIXES_FEATURE, true); 686 } catch (SAXException e) { 687 // Falls through 688 } 689 reader.setContentHandler(handler); 690 691 // Start pushing SAX events 692 reader.parse(input); 693 } finally { 694 if (!userReader) { 695 _readerManager.releaseXMLReader(reader); 696 } 697 } 698 } else if (source instanceof StAXSource) { 699 final StAXSource staxSource = (StAXSource)source; 700 StAXEvent2SAX staxevent2sax; 701 StAXStream2SAX staxStream2SAX; 702 if (staxSource.getXMLEventReader() != null) { 703 final XMLEventReader xmlEventReader = staxSource.getXMLEventReader(); 704 staxevent2sax = new StAXEvent2SAX(xmlEventReader); 705 staxevent2sax.setContentHandler(handler); 706 staxevent2sax.parse(); 707 handler.flushPending(); 708 } else if (staxSource.getXMLStreamReader() != null) { 709 final XMLStreamReader xmlStreamReader = staxSource.getXMLStreamReader(); 710 staxStream2SAX = new StAXStream2SAX(xmlStreamReader); 711 staxStream2SAX.setContentHandler(handler); 712 staxStream2SAX.parse(); 713 handler.flushPending(); 714 } 715 } else if (source instanceof DOMSource) { 716 final DOMSource domsrc = (DOMSource) source; 717 new DOM2TO(domsrc.getNode(), handler).parse(); 718 } else if (source instanceof XSLTCSource) { 719 final DOM dom = ((XSLTCSource) source).getDOM(null, _translet); 720 ((SAXImpl)dom).copy(handler); 721 } else { 722 ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_SOURCE_ERR); 723 throw new TransformerException(err.toString()); 724 } 725 } 726 727 /** 728 * Internal transformation method - uses the internal APIs of XSLTC 729 */ 730 private void transform(Source source, SerializationHandler handler, 731 String encoding) throws TransformerException 732 { 733 try { 734 /* 735 * According to JAXP1.2, new SAXSource()/StreamSource() 736 * should create an empty input tree, with a default root node. 737 * new DOMSource()creates an empty document using DocumentBuilder. 738 * newDocument(); Use DocumentBuilder.newDocument() for all 3 739 * situations, since there is no clear spec. how to create 740 * an empty tree when both SAXSource() and StreamSource() are used. 741 */ 742 if ((source instanceof StreamSource && source.getSystemId()==null 743 && ((StreamSource)source).getInputStream()==null && 744 ((StreamSource)source).getReader()==null)|| 745 (source instanceof SAXSource && 746 ((SAXSource)source).getInputSource()==null && 747 ((SAXSource)source).getXMLReader()==null )|| 748 (source instanceof DOMSource && 749 ((DOMSource)source).getNode()==null)){ 750 751 boolean supportCatalog = true; 752 753 DocumentBuilderFactory builderF = FactoryImpl.getDOMFactory(_useServicesMechanism); 754 try { 755 builderF.setFeature(XMLConstants.USE_CATALOG, _useCatalog); 756 } catch (ParserConfigurationException e) { 757 supportCatalog = false; 758 } 759 760 if (supportCatalog && _useCatalog) { 761 CatalogFeatures cf = (CatalogFeatures)_tfactory.getAttribute(JdkXmlFeatures.CATALOG_FEATURES); 762 if (cf != null) { 763 for (CatalogFeatures.Feature f : CatalogFeatures.Feature.values()) { 764 builderF.setAttribute(f.getPropertyName(), cf.get(f)); 765 } 766 } 767 } 768 769 DocumentBuilder builder = builderF.newDocumentBuilder(); 770 String systemID = source.getSystemId(); 771 source = new DOMSource(builder.newDocument()); 772 773 // Copy system ID from original, empty Source to new 774 if (systemID != null) { 775 source.setSystemId(systemID); 776 } 777 } 778 if (_isIdentity) { 779 transformIdentity(source, handler); 780 } else { 781 _translet.transform(getDOM(source), handler); 782 } 783 } catch (TransletException e) { 784 if (_errorListener != null) postErrorToListener(e.getMessage()); 785 throw new TransformerException(e); 786 } catch (RuntimeException e) { 787 if (_errorListener != null) postErrorToListener(e.getMessage()); 788 throw new TransformerException(e); 789 } catch (Exception e) { 790 if (_errorListener != null) postErrorToListener(e.getMessage()); 791 throw new TransformerException(e); 792 } finally { 793 _dtmManager = null; 794 } 795 796 // If we create an output stream for the Result, we need to close it after the transformation. 797 if (_ostream != null) { 798 try { 799 _ostream.close(); 800 } 801 catch (IOException e) {} 802 _ostream = null; 803 } 804 } 805 806 /** 807 * Implements JAXP's Transformer.getErrorListener() 808 * Get the error event handler in effect for the transformation. 809 * 810 * @return The error event handler currently in effect 811 */ 812 @Override 813 public ErrorListener getErrorListener() { 814 return _errorListener; 815 } 816 817 /** 818 * Implements JAXP's Transformer.setErrorListener() 819 * Set the error event listener in effect for the transformation. 820 * Register a message handler in the translet in order to forward 821 * xsl:messages to error listener. 822 * 823 * @param listener The error event listener to use 824 * @throws IllegalArgumentException 825 */ 826 @Override 827 public void setErrorListener(ErrorListener listener) 828 throws IllegalArgumentException { 829 if (listener == null) { 830 ErrorMsg err = new ErrorMsg(ErrorMsg.ERROR_LISTENER_NULL_ERR, 831 "Transformer"); 832 throw new IllegalArgumentException(err.toString()); 833 } 834 _errorListener = listener; 835 836 // Register a message handler to report xsl:messages 837 if (_translet != null) 838 _translet.setMessageHandler(new MessageHandler(_errorListener)); 839 } 840 841 /** 842 * Inform TrAX error listener of an error 843 */ 844 private void postErrorToListener(String message) { 845 try { 846 _errorListener.error(new TransformerException(message)); 847 } 848 catch (TransformerException e) { 849 // ignored - transformation cannot be continued 850 } 851 } 852 853 /** 854 * Inform TrAX error listener of a warning 855 */ 856 private void postWarningToListener(String message) { 857 try { 858 _errorListener.warning(new TransformerException(message)); 859 } 860 catch (TransformerException e) { 861 // ignored - transformation cannot be continued 862 } 863 } 864 865 /** 866 * Implements JAXP's Transformer.getOutputProperties(). 867 * Returns a copy of the output properties for the transformation. This is 868 * a set of layered properties. The first layer contains properties set by 869 * calls to setOutputProperty() and setOutputProperties() on this class, 870 * and the output settings defined in the stylesheet's <xsl:output> 871 * element makes up the second level, while the default XSLT output 872 * settings are returned on the third level. 873 * 874 * @return Properties in effect for this Transformer 875 */ 876 @Override 877 public Properties getOutputProperties() { 878 return (Properties) _properties.clone(); 879 } 880 881 /** 882 * Implements JAXP's Transformer.getOutputProperty(). 883 * Get an output property that is in effect for the transformation. The 884 * property specified may be a property that was set with setOutputProperty, 885 * or it may be a property specified in the stylesheet. 886 * 887 * @param name A non-null string that contains the name of the property 888 * @throws IllegalArgumentException if the property name is not known 889 */ 890 @Override 891 public String getOutputProperty(String name) 892 throws IllegalArgumentException 893 { 894 if (!validOutputProperty(name)) { 895 ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_UNKNOWN_PROP_ERR, name); 896 throw new IllegalArgumentException(err.toString()); 897 } 898 return _properties.getProperty(name); 899 } 900 901 /** 902 * Implements JAXP's Transformer.setOutputProperties(). 903 * Set the output properties for the transformation. These properties 904 * will override properties set in the Templates with xsl:output. 905 * Unrecognised properties will be quitely ignored. 906 * 907 * @param properties The properties to use for the Transformer 908 * @throws IllegalArgumentException Never, errors are ignored 909 */ 910 @Override 911 public void setOutputProperties(Properties properties) 912 throws IllegalArgumentException 913 { 914 if (properties != null) { 915 final Enumeration names = properties.propertyNames(); 916 917 while (names.hasMoreElements()) { 918 final String name = (String) names.nextElement(); 919 920 // Ignore lower layer properties 921 if (isDefaultProperty(name, properties)) continue; 922 923 if (validOutputProperty(name)) { 924 _properties.setProperty(name, properties.getProperty(name)); 925 } 926 else { 927 ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_UNKNOWN_PROP_ERR, name); 928 throw new IllegalArgumentException(err.toString()); 929 } 930 } 931 } 932 else { 933 _properties = _propertiesClone; 934 } 935 } 936 937 /** 938 * Implements JAXP's Transformer.setOutputProperty(). 939 * Get an output property that is in effect for the transformation. The 940 * property specified may be a property that was set with 941 * setOutputProperty(), or it may be a property specified in the stylesheet. 942 * 943 * @param name The name of the property to set 944 * @param value The value to assign to the property 945 * @throws IllegalArgumentException Never, errors are ignored 946 */ 947 @Override 948 public void setOutputProperty(String name, String value) 949 throws IllegalArgumentException 950 { 951 if (!validOutputProperty(name)) { 952 ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_UNKNOWN_PROP_ERR, name); 953 throw new IllegalArgumentException(err.toString()); 954 } 955 _properties.setProperty(name, value); 956 } 957 958 /** 959 * Internal method to pass any properties to the translet prior to 960 * initiating the transformation 961 */ 962 private void transferOutputProperties(AbstractTranslet translet) 963 { 964 // Return right now if no properties are set 965 if (_properties == null) return; 966 967 // Get a list of all the defined properties 968 Enumeration names = _properties.propertyNames(); 969 while (names.hasMoreElements()) { 970 // Note the use of get() instead of getProperty() 971 String name = (String) names.nextElement(); 972 String value = (String) _properties.get(name); 973 974 // Ignore default properties 975 if (value == null) continue; 976 977 // Pass property value to translet - override previous setting 978 if (name.equals(OutputKeys.ENCODING)) { 979 translet._encoding = value; 980 } 981 else if (name.equals(OutputKeys.METHOD)) { 982 translet._method = value; 983 } 984 else if (name.equals(OutputKeys.DOCTYPE_PUBLIC)) { 985 translet._doctypePublic = value; 986 } 987 else if (name.equals(OutputKeys.DOCTYPE_SYSTEM)) { 988 translet._doctypeSystem = value; 989 } 990 else if (name.equals(OutputKeys.MEDIA_TYPE)) { 991 translet._mediaType = value; 992 } 993 else if (name.equals(OutputKeys.STANDALONE)) { 994 translet._standalone = value; 995 } 996 else if (name.equals(OutputKeys.VERSION)) { 997 translet._version = value; 998 } 999 else if (name.equals(OutputKeys.OMIT_XML_DECLARATION)) { 1000 translet._omitHeader = 1001 (value != null && value.toLowerCase().equals("yes")); 1002 } 1003 else if (name.equals(OutputKeys.INDENT)) { 1004 translet._indent = 1005 (value != null && value.toLowerCase().equals("yes")); 1006 } 1007 else if (name.equals(OutputPropertiesFactory.S_BUILTIN_OLD_EXTENSIONS_UNIVERSAL +"indent-amount")) { 1008 if (value != null) { 1009 translet._indentamount = Integer.parseInt(value); 1010 } 1011 } 1012 else if (name.equals(OutputPropertiesFactory.S_BUILTIN_EXTENSIONS_UNIVERSAL +"indent-amount")) { 1013 if (value != null) { 1014 translet._indentamount = Integer.parseInt(value); 1015 } 1016 } 1017 else if (name.equals(OutputKeys.CDATA_SECTION_ELEMENTS)) { 1018 if (value != null) { 1019 translet._cdata = null; // clear previous setting 1020 StringTokenizer e = new StringTokenizer(value); 1021 while (e.hasMoreTokens()) { 1022 translet.addCdataElement(e.nextToken()); 1023 } 1024 } 1025 } 1026 else if (name.equals(OutputPropertiesFactory.ORACLE_IS_STANDALONE)) { 1027 if (value != null && value.equals("yes")) { 1028 translet._isStandalone = true; 1029 } 1030 } 1031 } 1032 } 1033 1034 /** 1035 * This method is used to pass any properties to the output handler 1036 * when running the identity transform. 1037 */ 1038 public void transferOutputProperties(SerializationHandler handler) 1039 { 1040 // Return right now if no properties are set 1041 if (_properties == null) return; 1042 1043 String doctypePublic = null; 1044 String doctypeSystem = null; 1045 1046 // Get a list of all the defined properties 1047 Enumeration names = _properties.propertyNames(); 1048 while (names.hasMoreElements()) { 1049 // Note the use of get() instead of getProperty() 1050 String name = (String) names.nextElement(); 1051 String value = (String) _properties.get(name); 1052 1053 // Ignore default properties 1054 if (value == null) continue; 1055 1056 // Pass property value to translet - override previous setting 1057 if (name.equals(OutputKeys.DOCTYPE_PUBLIC)) { 1058 doctypePublic = value; 1059 } 1060 else if (name.equals(OutputKeys.DOCTYPE_SYSTEM)) { 1061 doctypeSystem = value; 1062 } 1063 else if (name.equals(OutputKeys.MEDIA_TYPE)) { 1064 handler.setMediaType(value); 1065 } 1066 else if (name.equals(OutputKeys.STANDALONE)) { 1067 handler.setStandalone(value); 1068 } 1069 else if (name.equals(OutputKeys.VERSION)) { 1070 handler.setVersion(value); 1071 } 1072 else if (name.equals(OutputKeys.OMIT_XML_DECLARATION)) { 1073 handler.setOmitXMLDeclaration( 1074 value != null && value.toLowerCase().equals("yes")); 1075 } 1076 else if (name.equals(OutputKeys.INDENT)) { 1077 handler.setIndent( 1078 value != null && value.toLowerCase().equals("yes")); 1079 } 1080 else if (name.equals(OutputPropertiesFactory.S_BUILTIN_OLD_EXTENSIONS_UNIVERSAL +"indent-amount")) { 1081 if (value != null) { 1082 handler.setIndentAmount(Integer.parseInt(value)); 1083 } 1084 } 1085 else if (name.equals(OutputPropertiesFactory.S_BUILTIN_EXTENSIONS_UNIVERSAL +"indent-amount")) { 1086 if (value != null) { 1087 handler.setIndentAmount(Integer.parseInt(value)); 1088 } 1089 } 1090 else if (name.equals(OutputPropertiesFactory.ORACLE_IS_STANDALONE)) { 1091 if (value != null && value.equals("yes")) { 1092 handler.setIsStandalone(true); 1093 } 1094 } 1095 else if (name.equals(OutputKeys.CDATA_SECTION_ELEMENTS)) { 1096 if (value != null) { 1097 StringTokenizer e = new StringTokenizer(value); 1098 ArrayList<String> uriAndLocalNames = null; 1099 while (e.hasMoreTokens()) { 1100 final String token = e.nextToken(); 1101 1102 // look for the last colon, as the String may be 1103 // something like "http://abc.com:local" 1104 int lastcolon = token.lastIndexOf(':'); 1105 String uri; 1106 String localName; 1107 if (lastcolon > 0) { 1108 uri = token.substring(0, lastcolon); 1109 localName = token.substring(lastcolon+1); 1110 } else { 1111 // no colon at all, lets hope this is the 1112 // local name itself then 1113 uri = null; 1114 localName = token; 1115 } 1116 1117 if (uriAndLocalNames == null) { 1118 uriAndLocalNames = new ArrayList<>(); 1119 } 1120 // add the uri/localName as a pair, in that order 1121 uriAndLocalNames.add(uri); 1122 uriAndLocalNames.add(localName); 1123 } 1124 handler.setCdataSectionElements(uriAndLocalNames); 1125 } 1126 } 1127 } 1128 1129 // Call setDoctype() if needed 1130 if (doctypePublic != null || doctypeSystem != null) { 1131 handler.setDoctype(doctypeSystem, doctypePublic); 1132 } 1133 } 1134 1135 /** 1136 * Internal method to create the initial set of properties. There 1137 * are two layers of properties: the default layer and the base layer. 1138 * The latter contains properties defined in the stylesheet or by 1139 * the user using this API. 1140 */ 1141 private Properties createOutputProperties(Properties outputProperties) { 1142 final Properties defaults = new Properties(); 1143 setDefaults(defaults, "xml"); 1144 1145 // Copy propeties set in stylesheet to base 1146 final Properties base = new Properties(defaults); 1147 if (outputProperties != null) { 1148 final Enumeration names = outputProperties.propertyNames(); 1149 while (names.hasMoreElements()) { 1150 final String name = (String) names.nextElement(); 1151 base.setProperty(name, outputProperties.getProperty(name)); 1152 } 1153 } 1154 else { 1155 base.setProperty(OutputKeys.ENCODING, _translet._encoding); 1156 if (_translet._method != null) 1157 base.setProperty(OutputKeys.METHOD, _translet._method); 1158 } 1159 1160 // Update defaults based on output method 1161 final String method = base.getProperty(OutputKeys.METHOD); 1162 if (method != null) { 1163 if (method.equals("html")) { 1164 setDefaults(defaults,"html"); 1165 } 1166 else if (method.equals("text")) { 1167 setDefaults(defaults,"text"); 1168 } 1169 } 1170 1171 return base; 1172 } 1173 1174 /** 1175 * Internal method to get the default properties from the 1176 * serializer factory and set them on the property object. 1177 * @param props a java.util.Property object on which the properties are set. 1178 * @param method The output method type, one of "xml", "text", "html" ... 1179 */ 1180 private void setDefaults(Properties props, String method) 1181 { 1182 final Properties method_props = 1183 OutputPropertiesFactory.getDefaultMethodProperties(method); 1184 { 1185 final Enumeration names = method_props.propertyNames(); 1186 while (names.hasMoreElements()) 1187 { 1188 final String name = (String)names.nextElement(); 1189 props.setProperty(name, method_props.getProperty(name)); 1190 } 1191 } 1192 } 1193 /** 1194 * Verifies if a given output property name is a property defined in 1195 * the JAXP 1.1 / TrAX spec 1196 */ 1197 private boolean validOutputProperty(String name) { 1198 return (name.equals(OutputKeys.ENCODING) || 1199 name.equals(OutputKeys.METHOD) || 1200 name.equals(OutputKeys.INDENT) || 1201 name.equals(OutputKeys.DOCTYPE_PUBLIC) || 1202 name.equals(OutputKeys.DOCTYPE_SYSTEM) || 1203 name.equals(OutputKeys.CDATA_SECTION_ELEMENTS) || 1204 name.equals(OutputKeys.MEDIA_TYPE) || 1205 name.equals(OutputKeys.OMIT_XML_DECLARATION) || 1206 name.equals(OutputKeys.STANDALONE) || 1207 name.equals(OutputKeys.VERSION) || 1208 name.equals(OutputPropertiesFactory.ORACLE_IS_STANDALONE) || 1209 name.charAt(0) == '{'); 1210 } 1211 1212 /** 1213 * Checks if a given output property is default (2nd layer only) 1214 */ 1215 private boolean isDefaultProperty(String name, Properties properties) { 1216 return (properties.get(name) == null); 1217 } 1218 1219 /** 1220 * Implements JAXP's Transformer.setParameter() 1221 * Add a parameter for the transformation. The parameter is simply passed 1222 * on to the translet - no validation is performed - so any unused 1223 * parameters are quitely ignored by the translet. 1224 * 1225 * @param name The name of the parameter 1226 * @param value The value to assign to the parameter 1227 */ 1228 @Override 1229 public void setParameter(String name, Object value) { 1230 1231 if (value == null) { 1232 ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_INVALID_SET_PARAM_VALUE, name); 1233 throw new IllegalArgumentException(err.toString()); 1234 } 1235 1236 if (_isIdentity) { 1237 if (_parameters == null) { 1238 _parameters = new HashMap<>(); 1239 } 1240 _parameters.put(name, value); 1241 } 1242 else { 1243 _translet.addParameter(name, value); 1244 } 1245 } 1246 1247 /** 1248 * Implements JAXP's Transformer.clearParameters() 1249 * Clear all parameters set with setParameter. Clears the translet's 1250 * parameter stack. 1251 */ 1252 @Override 1253 public void clearParameters() { 1254 if (_isIdentity && _parameters != null) { 1255 _parameters.clear(); 1256 } 1257 else { 1258 _translet.clearParameters(); 1259 } 1260 } 1261 1262 /** 1263 * Implements JAXP's Transformer.getParameter() 1264 * Returns the value of a given parameter. Note that the translet will not 1265 * keep values for parameters that were not defined in the stylesheet. 1266 * 1267 * @param name The name of the parameter 1268 * @return An object that contains the value assigned to the parameter 1269 */ 1270 @Override 1271 public final Object getParameter(String name) { 1272 if (_isIdentity) { 1273 return (_parameters != null) ? _parameters.get(name) : null; 1274 } 1275 else { 1276 return _translet.getParameter(name); 1277 } 1278 } 1279 1280 /** 1281 * Implements JAXP's Transformer.getURIResolver() 1282 * Set the object currently used to resolve URIs used in document(). 1283 * 1284 * @return The URLResolver object currently in use 1285 */ 1286 @Override 1287 public URIResolver getURIResolver() { 1288 return _uriResolver; 1289 } 1290 1291 /** 1292 * Implements JAXP's Transformer.setURIResolver() 1293 * Set an object that will be used to resolve URIs used in document(). 1294 * 1295 * @param resolver The URIResolver to use in document() 1296 */ 1297 @Override 1298 public void setURIResolver(URIResolver resolver) { 1299 _uriResolver = resolver; 1300 } 1301 1302 /** 1303 * This class should only be used as a DOMCache for the translet if the 1304 * URIResolver has been set. 1305 * 1306 * The method implements XSLTC's DOMCache interface, which is used to 1307 * plug in an external document loader into a translet. This method acts 1308 * as an adapter between TrAX's URIResolver interface and XSLTC's 1309 * DOMCache interface. This approach is simple, but removes the 1310 * possibility of using external document caches with XSLTC. 1311 * 1312 * @param baseURI The base URI used by the document call. 1313 * @param href The href argument passed to the document function. 1314 * @param translet A reference to the translet requesting the document 1315 */ 1316 @Override 1317 public DOM retrieveDocument(String baseURI, String href, Translet translet) { 1318 try { 1319 // Argument to document function was: document(''); 1320 if (href.length() == 0) { 1321 href = baseURI; 1322 } 1323 1324 /* 1325 * Fix for bug 24188 1326 * Incase the _uriResolver.resolve(href,base) is null 1327 * try to still retrieve the document before returning null 1328 * and throwing the FileNotFoundException in 1329 * com.sun.org.apache.xalan.internal.xsltc.dom.LoadDocument 1330 * 1331 */ 1332 Source resolvedSource = null; 1333 if (_uriResolver != null) { 1334 resolvedSource = _uriResolver.resolve(href, baseURI); 1335 } 1336 1337 if (resolvedSource == null && _useCatalog && 1338 _catalogFeatures.get(CatalogFeatures.Feature.FILES) != null) { 1339 if (_catalogUriResolver == null) { 1340 _catalogUriResolver = CatalogManager.catalogUriResolver(_catalogFeatures); 1341 } 1342 resolvedSource = _catalogUriResolver.resolve(href, baseURI); 1343 } 1344 1345 if (resolvedSource == null) { 1346 StreamSource streamSource = new StreamSource( 1347 SystemIDResolver.getAbsoluteURI(href, baseURI)); 1348 return getDOM(streamSource) ; 1349 } 1350 1351 return getDOM(resolvedSource); 1352 } 1353 catch (TransformerException e) { 1354 if (_errorListener != null) 1355 postErrorToListener("File not found: " + e.getMessage()); 1356 return(null); 1357 } 1358 } 1359 1360 /** 1361 * Receive notification of a recoverable error. 1362 * The transformer must continue to provide normal parsing events after 1363 * invoking this method. It should still be possible for the application 1364 * to process the document through to the end. 1365 * 1366 * @param e The warning information encapsulated in a transformer 1367 * exception. 1368 * @throws TransformerException if the application chooses to discontinue 1369 * the transformation (always does in our case). 1370 */ 1371 @Override 1372 public void error(TransformerException e) 1373 throws TransformerException 1374 { 1375 Throwable wrapped = e.getException(); 1376 if (wrapped != null) { 1377 System.err.println(new ErrorMsg(ErrorMsg.ERROR_PLUS_WRAPPED_MSG, 1378 e.getMessageAndLocation(), 1379 wrapped.getMessage())); 1380 } else { 1381 System.err.println(new ErrorMsg(ErrorMsg.ERROR_MSG, 1382 e.getMessageAndLocation())); 1383 } 1384 throw e; 1385 } 1386 1387 /** 1388 * Receive notification of a non-recoverable error. 1389 * The application must assume that the transformation cannot continue 1390 * after the Transformer has invoked this method, and should continue 1391 * (if at all) only to collect addition error messages. In fact, 1392 * Transformers are free to stop reporting events once this method has 1393 * been invoked. 1394 * 1395 * @param e The warning information encapsulated in a transformer 1396 * exception. 1397 * @throws TransformerException if the application chooses to discontinue 1398 * the transformation (always does in our case). 1399 */ 1400 @Override 1401 public void fatalError(TransformerException e) 1402 throws TransformerException 1403 { 1404 Throwable wrapped = e.getException(); 1405 if (wrapped != null) { 1406 System.err.println(new ErrorMsg(ErrorMsg.FATAL_ERR_PLUS_WRAPPED_MSG, 1407 e.getMessageAndLocation(), 1408 wrapped.getMessage())); 1409 } else { 1410 System.err.println(new ErrorMsg(ErrorMsg.FATAL_ERR_MSG, 1411 e.getMessageAndLocation())); 1412 } 1413 throw e; 1414 } 1415 1416 /** 1417 * Receive notification of a warning. 1418 * Transformers can use this method to report conditions that are not 1419 * errors or fatal errors. The default behaviour is to take no action. 1420 * After invoking this method, the Transformer must continue with the 1421 * transformation. It should still be possible for the application to 1422 * process the document through to the end. 1423 * 1424 * @param e The warning information encapsulated in a transformer 1425 * exception. 1426 * @throws TransformerException if the application chooses to discontinue 1427 * the transformation (never does in our case). 1428 */ 1429 @Override 1430 public void warning(TransformerException e) 1431 throws TransformerException 1432 { 1433 Throwable wrapped = e.getException(); 1434 if (wrapped != null) { 1435 System.err.println(new ErrorMsg(ErrorMsg.WARNING_PLUS_WRAPPED_MSG, 1436 e.getMessageAndLocation(), 1437 wrapped.getMessage())); 1438 } else { 1439 System.err.println(new ErrorMsg(ErrorMsg.WARNING_MSG, 1440 e.getMessageAndLocation())); 1441 } 1442 } 1443 1444 /** 1445 * This method resets the Transformer to its original configuration 1446 * Transformer code is reset to the same state it was when it was 1447 * created 1448 * @since 1.5 1449 */ 1450 @Override 1451 public void reset() { 1452 1453 _method = null; 1454 _encoding = null; 1455 _sourceSystemId = null; 1456 _errorListener = this; 1457 _uriResolver = null; 1458 _dom = null; 1459 _parameters = null; 1460 _indentNumber = 0; 1461 setOutputProperties (null); 1462 _tohFactory = null; 1463 _ostream = null; 1464 1465 } 1466 }