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