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