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