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