1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 /* 19 * $Id: TransformerImpl.java 475979 2006-11-16 23:32:48Z minchau $ 20 */ 21 package org.apache.xalan.transformer; 22 23 import java.io.IOException; 24 import java.io.StringWriter; 25 import java.util.Enumeration; 26 import java.util.Properties; 27 import java.util.Stack; 28 import java.util.StringTokenizer; 29 import java.util.Vector; 30 31 import javax.xml.parsers.DocumentBuilder; 32 import javax.xml.parsers.DocumentBuilderFactory; 33 import javax.xml.parsers.ParserConfigurationException; 34 import javax.xml.transform.ErrorListener; 35 import javax.xml.transform.OutputKeys; 36 import javax.xml.transform.Result; 37 import javax.xml.transform.Source; 38 import javax.xml.transform.SourceLocator; 39 import javax.xml.transform.Transformer; 40 import javax.xml.transform.TransformerException; 41 import javax.xml.transform.URIResolver; 42 import javax.xml.transform.dom.DOMResult; 43 import javax.xml.transform.dom.DOMSource; 44 import javax.xml.transform.sax.SAXResult; 45 import javax.xml.transform.sax.SAXSource; 46 import javax.xml.transform.stream.StreamResult; 47 import javax.xml.transform.stream.StreamSource; 48 49 import org.apache.xalan.extensions.ExtensionsTable; 50 import org.apache.xalan.res.XSLMessages; 51 import org.apache.xalan.res.XSLTErrorResources; 52 import org.apache.xml.serializer.Method; 53 import org.apache.xml.serializer.Serializer; 54 import org.apache.xml.serializer.SerializerFactory; 55 import org.apache.xalan.templates.AVT; 56 import org.apache.xalan.templates.Constants; 57 import org.apache.xalan.templates.ElemAttributeSet; 58 import org.apache.xalan.templates.ElemForEach; 59 import org.apache.xalan.templates.ElemSort; 60 import org.apache.xalan.templates.ElemTemplate; 61 import org.apache.xalan.templates.ElemTemplateElement; 62 import org.apache.xalan.templates.ElemTextLiteral; 63 import org.apache.xalan.templates.ElemVariable; 64 import org.apache.xalan.templates.OutputProperties; 65 import org.apache.xalan.templates.Stylesheet; 66 import org.apache.xalan.templates.StylesheetComposed; 67 import org.apache.xalan.templates.StylesheetRoot; 68 import org.apache.xalan.templates.XUnresolvedVariable; 69 import org.apache.xml.dtm.DTM; 70 import org.apache.xml.dtm.DTMIterator; 71 import org.apache.xml.dtm.DTMManager; 72 import org.apache.xml.dtm.DTMWSFilter; 73 import org.apache.xml.serializer.ToSAXHandler; 74 import org.apache.xml.serializer.ToTextStream; 75 import org.apache.xml.serializer.ToXMLSAXHandler; 76 import org.apache.xml.serializer.SerializationHandler; 77 import org.apache.xml.utils.BoolStack; 78 import org.apache.xml.utils.DOMBuilder; 79 import org.apache.xml.utils.NodeVector; 80 import org.apache.xml.utils.ObjectPool; 81 import org.apache.xml.utils.ObjectStack; 82 import org.apache.xml.utils.QName; 83 import org.apache.xml.utils.SAXSourceLocator; 84 import org.apache.xml.utils.ThreadControllerWrapper; 85 import org.apache.xpath.Arg; 86 import org.apache.xpath.ExtensionsProvider; 87 import org.apache.xpath.VariableStack; 88 import org.apache.xpath.XPathContext; 89 import org.apache.xpath.functions.FuncExtFunction; 90 import org.apache.xpath.objects.XObject; 91 import org.xml.sax.Attributes; 92 import org.xml.sax.ContentHandler; 93 import org.xml.sax.SAXException; 94 import org.xml.sax.SAXNotRecognizedException; 95 import org.xml.sax.SAXNotSupportedException; 96 import org.xml.sax.ext.LexicalHandler; 97 98 /** 99 * This class implements the 100 * {@link javax.xml.transform.Transformer} interface, and is the core 101 * representation of the transformation execution.</p> 102 * @xsl.usage advanced 103 */ 104 public class TransformerImpl extends Transformer 105 implements Runnable, DTMWSFilter, ExtensionsProvider, org.apache.xml.serializer.SerializerTrace 106 { 107 108 // Synch object to gaurd against setting values from the TrAX interface 109 // or reentry while the transform is going on. 110 111 /** NEEDSDOC Field m_reentryGuard */ 112 private Boolean m_reentryGuard = new Boolean(true); 113 114 /** 115 * This is null unless we own the stream. 116 */ 117 private java.io.FileOutputStream m_outputStream = null; 118 119 /** The thread that the transformer is running on. */ 120 private Thread m_transformThread; 121 122 /** The base URL of the source tree. */ 123 private String m_urlOfSource = null; 124 125 /** The Result object at the start of the transform, if any. */ 126 private Result m_outputTarget = null; 127 128 /** 129 * The output format object set by the user. May be null. 130 */ 131 private OutputProperties m_outputFormat; 132 133 134 /** 135 * The content handler for the source input tree. 136 */ 137 ContentHandler m_inputContentHandler; 138 139 /** 140 * The content handler for the result tree. 141 */ 142 private ContentHandler m_outputContentHandler = null; 143 144 // /* 145 // * Use member variable to store param variables as they're 146 // * being created, use member variable so we don't 147 // * have to create a new vector every time. 148 // */ 149 // private Vector m_newVars = new Vector(); 150 151 /** 152 * A pool of ResultTreeHandlers, for serialization of a subtree to text. 153 * Please note that each of these also holds onto a Text Serializer. 154 */ 155 private ObjectPool m_textResultHandlerObjectPool = 156 new ObjectPool(ToTextStream.class); 157 158 /** 159 * Related to m_textResultHandlerObjectPool, this is a pool of 160 * StringWriters, which are passed to the Text Serializers. 161 * (I'm not sure if this is really needed any more. -sb) 162 */ 163 private ObjectPool m_stringWriterObjectPool = 164 new ObjectPool(StringWriter.class); 165 166 /** 167 * A static text format object, which can be used over and 168 * over to create the text serializers. 169 */ 170 private OutputProperties m_textformat = new OutputProperties(Method.TEXT); 171 172 // Commenteded out in response to problem reported by 173 // Nicola Brown <Nicola.Brown@jacobsrimell.com> 174 // /** 175 // * Flag to let us know if an exception should be reported inside the 176 // * postExceptionFromThread method. This is needed if the transform is 177 // * being generated from SAX events, and thus there is no central place 178 // * to report the exception from. (An exception is usually picked up in 179 // * the main thread from the transform thread in {@link #transform(Source source)} 180 // * from {@link #getExceptionThrown()}. ) 181 // */ 182 // private boolean m_reportInPostExceptionFromThread = false; 183 184 /** 185 * A node vector used as a stack to track the current 186 * ElemTemplateElement. Needed for the 187 * org.apache.xalan.transformer.TransformState interface, 188 * so a tool can discover the calling template. Note the use of an array 189 * for this limits the recursion depth to 4K. 190 */ 191 ObjectStack m_currentTemplateElements 192 = new ObjectStack(XPathContext.RECURSIONLIMIT); 193 194 /** The top of the currentTemplateElements stack. */ 195 //int m_currentTemplateElementsTop = 0; 196 197 /** 198 * A node vector used as a stack to track the current 199 * ElemTemplate that was matched. 200 * Needed for the 201 * org.apache.xalan.transformer.TransformState interface, 202 * so a tool can discover the matched template 203 */ 204 Stack m_currentMatchTemplates = new Stack(); 205 206 /** 207 * A node vector used as a stack to track the current 208 * node that was matched. 209 * Needed for the 210 * org.apache.xalan.transformer.TransformState interface, 211 * so a tool can discover the matched 212 * node. 213 */ 214 NodeVector m_currentMatchedNodes = new NodeVector(); 215 216 /** 217 * The root of a linked set of stylesheets. 218 */ 219 private StylesheetRoot m_stylesheetRoot = null; 220 221 /** 222 * If this is set to true, do not warn about pattern 223 * match conflicts. 224 */ 225 private boolean m_quietConflictWarnings = true; 226 227 /** 228 * The liason to the XML parser, so the XSL processor 229 * can handle included files, and the like, and do the 230 * initial parse of the XSL document. 231 */ 232 private XPathContext m_xcontext; 233 234 /** 235 * Output handler to bottleneck SAX events. 236 */ 237 private SerializationHandler m_serializationHandler; 238 239 /** The key manager, which manages xsl:keys. */ 240 private KeyManager m_keyManager = new KeyManager(); 241 242 /** 243 * Stack for the purposes of flagging infinite recursion with 244 * attribute sets. 245 */ 246 Stack m_attrSetStack = null; 247 248 /** 249 * The table of counters for xsl:number support. 250 */ 251 CountersTable m_countersTable = null; 252 253 /** 254 * Is > 0 when we're processing a for-each. 255 */ 256 BoolStack m_currentTemplateRuleIsNull = new BoolStack(); 257 258 /** 259 * Keeps track of the result delivered by any EXSLT <code>func:result</code> 260 * instruction that has been executed for the currently active EXSLT 261 * <code>func:function</code> 262 */ 263 ObjectStack m_currentFuncResult = new ObjectStack(); 264 265 /** 266 * The message manager, which manages error messages, warning 267 * messages, and other types of message events. 268 */ 269 private MsgMgr m_msgMgr; 270 271 /** 272 * The flag for the setting of the optimize feature; 273 * This flag should have the same value as the FEATURE_OPTIMIZE feature 274 * which is set by the TransformerFactory.setAttribut() method before a 275 * Transformer is created 276 */ 277 private boolean m_optimizer = true; 278 279 /** 280 * The flag for the setting of the incremental feature; 281 * This flag should have the same value as the FEATURE_INCREMENTAL feature 282 * which is set by the TransformerFactory.setAttribut() method before a 283 * Transformer is created 284 */ 285 private boolean m_incremental = false; 286 287 /** 288 * The flag for the setting of the source_location feature; 289 * This flag should have the same value as the FEATURE_SOURCE_LOCATION feature 290 * which is set by the TransformerFactory.setAttribut() method before a 291 * Transformer is created 292 */ 293 private boolean m_source_location = false; 294 295 /** 296 * The SAX error handler, where errors and warnings are sent. 297 */ 298 private ErrorListener m_errorHandler = 299 new org.apache.xml.utils.DefaultErrorHandler(false); 300 301 /** 302 * If the transform thread throws an exception, the exception needs to 303 * be stashed away so that the main thread can pass it on to the 304 * client. 305 */ 306 private Exception m_exceptionThrown = null; 307 308 /** 309 * This is needed for support of setSourceTreeDocForThread(Node doc), 310 * which must be called in order for the transform thread's run 311 * method to obtain the root of the source tree to be transformed. 312 */ 313 private int m_doc; 314 315 /** Flag to to tell if the tranformer needs to be reset. */ 316 private boolean m_hasBeenReset = false; 317 318 /** NEEDSDOC Field m_shouldReset */ 319 private boolean m_shouldReset = true; 320 321 /** 322 * A stack of current template modes. 323 */ 324 private Stack m_modes = new Stack(); 325 326 //========================================================== 327 // SECTION: Constructor 328 //========================================================== 329 330 /** 331 * Construct a TransformerImpl. 332 * 333 * @param stylesheet The root of the stylesheet tree. 334 */ TransformerImpl(StylesheetRoot stylesheet)335 public TransformerImpl(StylesheetRoot stylesheet) 336 // throws javax.xml.transform.TransformerException 337 { 338 m_optimizer = stylesheet.getOptimizer(); 339 m_incremental = stylesheet.getIncremental(); 340 m_source_location = stylesheet.getSource_location(); 341 setStylesheet(stylesheet); 342 XPathContext xPath = new XPathContext(this); 343 xPath.setIncremental(m_incremental); 344 xPath.getDTMManager().setIncremental(m_incremental); 345 xPath.setSource_location(m_source_location); 346 xPath.getDTMManager().setSource_location(m_source_location); 347 348 if (stylesheet.isSecureProcessing()) 349 xPath.setSecureProcessing(true); 350 351 setXPathContext(xPath); 352 getXPathContext().setNamespaceContext(stylesheet); 353 } 354 355 // ================ ExtensionsTable =================== 356 357 /** 358 * The table of ExtensionHandlers. 359 */ 360 private ExtensionsTable m_extensionsTable = null; 361 362 /** 363 * Get the extensions table object. 364 * 365 * @return The extensions table. 366 */ getExtensionsTable()367 public ExtensionsTable getExtensionsTable() 368 { 369 return m_extensionsTable; 370 } 371 372 /** 373 * If the stylesheet contains extensions, set the extensions table object. 374 * 375 * 376 * @param sroot The stylesheet. 377 * @throws javax.xml.transform.TransformerException 378 */ setExtensionsTable(StylesheetRoot sroot)379 void setExtensionsTable(StylesheetRoot sroot) 380 throws javax.xml.transform.TransformerException 381 { 382 try 383 { 384 if (sroot.getExtensions() != null) 385 //only load extensions if secureProcessing is disabled 386 if(!sroot.isSecureProcessing()) 387 m_extensionsTable = new ExtensionsTable(sroot); 388 } 389 catch (javax.xml.transform.TransformerException te) 390 {te.printStackTrace();} 391 } 392 393 //== Implementation of the XPath ExtensionsProvider interface. 394 functionAvailable(String ns, String funcName)395 public boolean functionAvailable(String ns, String funcName) 396 throws javax.xml.transform.TransformerException 397 { 398 return getExtensionsTable().functionAvailable(ns, funcName); 399 } 400 elementAvailable(String ns, String elemName)401 public boolean elementAvailable(String ns, String elemName) 402 throws javax.xml.transform.TransformerException 403 { 404 return getExtensionsTable().elementAvailable(ns, elemName); 405 } 406 extFunction(String ns, String funcName, Vector argVec, Object methodKey)407 public Object extFunction(String ns, String funcName, 408 Vector argVec, Object methodKey) 409 throws javax.xml.transform.TransformerException 410 {//System.out.println("TransImpl.extFunction() " + ns + " " + funcName +" " + getExtensionsTable()); 411 return getExtensionsTable().extFunction(ns, funcName, 412 argVec, methodKey, 413 getXPathContext().getExpressionContext()); 414 } 415 extFunction(FuncExtFunction extFunction, Vector argVec)416 public Object extFunction(FuncExtFunction extFunction, Vector argVec) 417 throws javax.xml.transform.TransformerException 418 { 419 return getExtensionsTable().extFunction(extFunction, argVec, 420 getXPathContext().getExpressionContext()); 421 } 422 423 //========================= 424 425 /** 426 * Reset the state. This needs to be called after a process() call 427 * is invoked, if the processor is to be used again. 428 */ reset()429 public void reset() 430 { 431 432 if (!m_hasBeenReset && m_shouldReset) 433 { 434 m_hasBeenReset = true; 435 436 if (this.m_outputStream != null) 437 { 438 try 439 { 440 m_outputStream.close(); 441 } 442 catch (java.io.IOException ioe){} 443 } 444 445 m_outputStream = null; 446 447 // I need to look more carefully at which of these really 448 // needs to be reset. 449 m_countersTable = null; 450 451 m_xcontext.reset(); 452 453 m_xcontext.getVarStack().reset(); 454 resetUserParameters(); 455 456 457 m_currentTemplateElements.removeAllElements(); 458 m_currentMatchTemplates.removeAllElements(); 459 m_currentMatchedNodes.removeAllElements(); 460 461 m_serializationHandler = null; 462 m_outputTarget = null; 463 m_keyManager = new KeyManager(); 464 m_attrSetStack = null; 465 m_countersTable = null; 466 m_currentTemplateRuleIsNull = new BoolStack(); 467 // m_xmlSource = null; // android-removed 468 m_doc = DTM.NULL; 469 // m_isTransformDone = false; // android-removed 470 m_transformThread = null; 471 472 // m_inputContentHandler = null; 473 // For now, reset the document cache each time. 474 m_xcontext.getSourceTreeManager().reset(); 475 } 476 477 // m_reportInPostExceptionFromThread = false; 478 } 479 480 // ========= Transformer Interface Implementation ========== 481 482 /** 483 * Get the thread that the transform process is on. 484 * 485 * @return The thread that the transform process is on, or null. 486 * @xsl.usage internal 487 */ getTransformThread()488 public Thread getTransformThread() 489 { 490 return m_transformThread; 491 } 492 493 /** 494 * Get the thread that the transform process is on. 495 * 496 * @param t The transform thread, may be null. 497 * @xsl.usage internal 498 */ setTransformThread(Thread t)499 public void setTransformThread(Thread t) 500 { 501 m_transformThread = t; 502 } 503 504 /** NEEDSDOC Field m_hasTransformThreadErrorCatcher */ 505 private boolean m_hasTransformThreadErrorCatcher = false; 506 507 /** 508 * Return true if the transform was initiated from the transform method, 509 * otherwise it was probably done from a pure parse events. 510 * 511 * NEEDSDOC ($objectName$) @return 512 */ hasTransformThreadErrorCatcher()513 public boolean hasTransformThreadErrorCatcher() 514 { 515 return m_hasTransformThreadErrorCatcher; 516 } 517 518 /** 519 * Process the source tree to SAX parse events. 520 * @param source The input for the source tree. 521 * 522 * @throws TransformerException 523 */ transform(Source source)524 public void transform(Source source) throws TransformerException 525 { 526 transform(source, true); 527 } 528 529 /** 530 * Process the source tree to SAX parse events. 531 * @param source The input for the source tree. 532 * @param shouldRelease Flag indicating whether to release DTMManager. 533 * 534 * @throws TransformerException 535 */ transform(Source source, boolean shouldRelease)536 public void transform(Source source, boolean shouldRelease) throws TransformerException 537 { 538 539 try 540 { 541 542 // Patch for bugzilla #13863. If we don't reset the namespaceContext 543 // then we will get a NullPointerException if transformer is reused 544 // (for stylesheets that use xsl:key). Not sure if this should go 545 // here or in reset(). -is 546 if(getXPathContext().getNamespaceContext() == null){ 547 getXPathContext().setNamespaceContext(getStylesheet()); 548 } 549 String base = source.getSystemId(); 550 551 // If no systemID of the source, use the base of the stylesheet. 552 if(null == base) 553 { 554 base = m_stylesheetRoot.getBaseIdentifier(); 555 } 556 557 // As a last resort, use the current user dir. 558 if(null == base) 559 { 560 String currentDir = ""; 561 try { 562 currentDir = System.getProperty("user.dir"); 563 } 564 catch (SecurityException se) {}// user.dir not accessible from applet 565 566 if (currentDir.startsWith(java.io.File.separator)) 567 base = "file://" + currentDir; 568 else 569 base = "file:///" + currentDir; 570 571 base = base + java.io.File.separatorChar 572 + source.getClass().getName(); 573 } 574 setBaseURLOfSource(base); 575 DTMManager mgr = m_xcontext.getDTMManager(); 576 /* 577 * According to JAXP1.2, new SAXSource()/StreamSource() 578 * should create an empty input tree, with a default root node. 579 * new DOMSource()creates an empty document using DocumentBuilder. 580 * newDocument(); Use DocumentBuilder.newDocument() for all 3 situations, 581 * since there is no clear spec. how to create an empty tree when 582 * both SAXSource() and StreamSource() are used. 583 */ 584 if ((source instanceof StreamSource && source.getSystemId()==null && 585 ((StreamSource)source).getInputStream()==null && 586 ((StreamSource)source).getReader()==null)|| 587 (source instanceof SAXSource && 588 ((SAXSource)source).getInputSource()==null && 589 ((SAXSource)source).getXMLReader()==null )|| 590 (source instanceof DOMSource && ((DOMSource)source).getNode()==null)){ 591 try { 592 DocumentBuilderFactory builderF = 593 DocumentBuilderFactory.newInstance(); 594 DocumentBuilder builder = builderF.newDocumentBuilder(); 595 String systemID = source.getSystemId(); 596 source = new DOMSource(builder.newDocument()); 597 598 // Copy system ID from original, empty Source to new Source 599 if (systemID != null) { 600 source.setSystemId(systemID); 601 } 602 } catch (ParserConfigurationException e) { 603 fatalError(e); 604 } 605 } 606 DTM dtm = mgr.getDTM(source, false, this, true, true); 607 dtm.setDocumentBaseURI(base); 608 609 boolean hardDelete = true; // %REVIEW% I have to think about this. -sb 610 611 try 612 { 613 // NOTE: This will work because this is _NOT_ a shared DTM, and thus has 614 // only a single Document node. If it could ever be an RTF or other 615 // shared DTM, look at dtm.getDocumentRoot(nodeHandle). 616 this.transformNode(dtm.getDocument()); 617 } 618 finally 619 { 620 if (shouldRelease) 621 mgr.release(dtm, hardDelete); 622 } 623 624 // Kick off the parse. When the ContentHandler gets 625 // the startDocument event, it will call transformNode( node ). 626 // reader.parse( xmlSource ); 627 // This has to be done to catch exceptions thrown from 628 // the transform thread spawned by the STree handler. 629 Exception e = getExceptionThrown(); 630 631 if (null != e) 632 { 633 if (e instanceof javax.xml.transform.TransformerException) 634 { 635 throw (javax.xml.transform.TransformerException) e; 636 } 637 else if (e instanceof org.apache.xml.utils.WrappedRuntimeException) 638 { 639 fatalError( 640 ((org.apache.xml.utils.WrappedRuntimeException) e).getException()); 641 } 642 else 643 { 644 throw new javax.xml.transform.TransformerException(e); 645 } 646 } 647 else if (null != m_serializationHandler) 648 { 649 m_serializationHandler.endDocument(); 650 } 651 } 652 catch (org.apache.xml.utils.WrappedRuntimeException wre) 653 { 654 Throwable throwable = wre.getException(); 655 656 while (throwable 657 instanceof org.apache.xml.utils.WrappedRuntimeException) 658 { 659 throwable = 660 ((org.apache.xml.utils.WrappedRuntimeException) throwable).getException(); 661 } 662 663 fatalError(throwable); 664 } 665 666 // Patch attributed to David Eisenberg <david@catcode.com> 667 catch (org.xml.sax.SAXParseException spe) 668 { 669 fatalError(spe); 670 } 671 catch (org.xml.sax.SAXException se) 672 { 673 m_errorHandler.fatalError(new TransformerException(se)); 674 } 675 finally 676 { 677 m_hasTransformThreadErrorCatcher = false; 678 679 // This looks to be redundent to the one done in TransformNode. 680 reset(); 681 } 682 } 683 fatalError(Throwable throwable)684 private void fatalError(Throwable throwable) throws TransformerException 685 { 686 if (throwable instanceof org.xml.sax.SAXParseException) 687 m_errorHandler.fatalError(new TransformerException(throwable.getMessage(),new SAXSourceLocator((org.xml.sax.SAXParseException)throwable))); 688 else 689 m_errorHandler.fatalError(new TransformerException(throwable)); 690 691 } 692 693 /** 694 * Get the base URL of the source. 695 * 696 * 697 * NEEDSDOC @param base 698 * @return The base URL of the source tree, or null. 699 */ setBaseURLOfSource(String base)700 public void setBaseURLOfSource(String base) 701 { 702 m_urlOfSource = base; 703 } 704 705 /** 706 * Get an output property that is in effect for the 707 * transformation. The property specified may be a property 708 * that was set with setOutputProperty, or it may be a 709 * property specified in the stylesheet. 710 * 711 * NEEDSDOC @param qnameString 712 * 713 * @return The string value of the output property, or null 714 * if no property was found. 715 * 716 * @throws IllegalArgumentException If the property is not supported. 717 * 718 * @see javax.xml.transform.OutputKeys 719 */ getOutputProperty(String qnameString)720 public String getOutputProperty(String qnameString) 721 throws IllegalArgumentException 722 { 723 724 String value = null; 725 OutputProperties props = getOutputFormat(); 726 727 value = props.getProperty(qnameString); 728 729 if (null == value) 730 { 731 if (!OutputProperties.isLegalPropertyKey(qnameString)) 732 throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_OUTPUT_PROPERTY_NOT_RECOGNIZED, new Object[]{qnameString})); //"output property not recognized: " 733 //+ qnameString); 734 } 735 736 return value; 737 } 738 739 /** 740 * Get the value of a property, without using the default properties. This 741 * can be used to test if a property has been explicitly set by the stylesheet 742 * or user. 743 * 744 * NEEDSDOC @param qnameString 745 * 746 * @return The value of the property, or null if not found. 747 * 748 * @throws IllegalArgumentException If the property is not supported, 749 * and is not namespaced. 750 */ getOutputPropertyNoDefault(String qnameString)751 public String getOutputPropertyNoDefault(String qnameString) 752 throws IllegalArgumentException 753 { 754 755 String value = null; 756 OutputProperties props = getOutputFormat(); 757 758 value = (String) props.getProperties().get(qnameString); 759 760 if (null == value) 761 { 762 if (!OutputProperties.isLegalPropertyKey(qnameString)) 763 throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_OUTPUT_PROPERTY_NOT_RECOGNIZED, new Object[]{qnameString})); //"output property not recognized: " 764 // + qnameString); 765 } 766 767 return value; 768 } 769 770 /** 771 * This method is used to set or override the value 772 * of the effective xsl:output attribute values 773 * specified in the stylesheet. 774 * <p> 775 * The recognized standard output properties are: 776 * <ul> 777 * <li>cdata-section-elements 778 * <li>doctype-system 779 * <li>doctype-public 780 * <li>indent 781 * <li>media-type 782 * <li>method 783 * <li>omit-xml-declaration 784 * <li>standalone 785 * <li>version 786 * </ul> 787 * <p> 788 * For example: 789 * <pre> 790 * tran.setOutputProperty("standalone", "yes"); 791 * </pre> 792 * <p> 793 * In the case of the cdata-section-elements property, 794 * the value should be a whitespace separated list of 795 * element names. The element name is the local name 796 * of the element, if it is in no namespace, or, the URI 797 * in braces followed immediately by the local name 798 * if the element is in that namespace. For example: 799 * <pre> 800 * tran.setOutputProperty( 801 * "cdata-section-elements", 802 * "elem1 {http://example.uri}elem2 elem3"); 803 * </pre> 804 * <p> 805 * The recognized Xalan extension elements are: 806 * <ul> 807 * <li>content-handler 808 * <li>entities 809 * <li>indent-amount 810 * <li>line-separator 811 * <li>omit-meta-tag 812 * <li>use-url-escaping 813 * </ul> 814 * <p> 815 * These must be in the extension namespace of 816 * "http://xml.apache.org/xalan". This is accomplished 817 * by putting the namespace URI in braces before the 818 * property name, for example: 819 * <pre> 820 * tran.setOutputProperty( 821 * "{http://xml.apache.org/xalan}line-separator" , 822 * "\n"); 823 * </pre> 824 * 825 * @param name The property name. 826 * @param value The requested value for the property. 827 * @throws IllegalArgumentException if the property name is not legal. 828 */ setOutputProperty(String name, String value)829 public void setOutputProperty(String name, String value) 830 throws IllegalArgumentException 831 { 832 833 synchronized (m_reentryGuard) 834 { 835 836 // Get the output format that was set by the user, otherwise get the 837 // output format from the stylesheet. 838 if (null == m_outputFormat) 839 { 840 m_outputFormat = 841 (OutputProperties) getStylesheet().getOutputComposed().clone(); 842 } 843 844 if (!OutputProperties.isLegalPropertyKey(name)) 845 throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_OUTPUT_PROPERTY_NOT_RECOGNIZED, new Object[]{name})); //"output property not recognized: " 846 //+ name); 847 848 m_outputFormat.setProperty(name, value); 849 } 850 } 851 852 /** 853 * Set the output properties for the transformation. These 854 * properties will override properties set in the templates 855 * with xsl:output. 856 * 857 * <p>If argument to this function is null, any properties 858 * previously set will be removed.</p> 859 * 860 * @param oformat A set of output properties that will be 861 * used to override any of the same properties in effect 862 * for the transformation. 863 * 864 * @see javax.xml.transform.OutputKeys 865 * @see java.util.Properties 866 * 867 * @throws IllegalArgumentException if any of the argument keys are not 868 * recognized and are not namespace qualified. 869 */ setOutputProperties(Properties oformat)870 public void setOutputProperties(Properties oformat) 871 throws IllegalArgumentException 872 { 873 874 synchronized (m_reentryGuard) 875 { 876 if (null != oformat) 877 { 878 879 // See if an *explicit* method was set. 880 String method = (String) oformat.get(OutputKeys.METHOD); 881 882 if (null != method) 883 m_outputFormat = new OutputProperties(method); 884 else if(m_outputFormat==null) 885 m_outputFormat = new OutputProperties(); 886 887 m_outputFormat.copyFrom(oformat); 888 // copyFrom does not set properties that have been already set, so 889 // this must be called after, which is a bit in the reverse from 890 // what one might think. 891 m_outputFormat.copyFrom(m_stylesheetRoot.getOutputProperties()); 892 } 893 else { 894 // if oformat is null JAXP says that any props previously set are removed 895 // and we are to revert back to those in the templates object (i.e. Stylesheet). 896 m_outputFormat = null; 897 } 898 } 899 } 900 901 /** 902 * Get a copy of the output properties for the transformation. These 903 * properties will override properties set in the templates 904 * with xsl:output. 905 * 906 * <p>Note that mutation of the Properties object returned will not 907 * effect the properties that the transformation contains.</p> 908 * 909 * @return A copy of the set of output properties in effect 910 * for the next transformation. 911 * 912 * NEEDSDOC ($objectName$) @return 913 */ getOutputProperties()914 public Properties getOutputProperties() 915 { 916 return (Properties) getOutputFormat().getProperties().clone(); 917 } 918 919 /** 920 * Create a result ContentHandler from a Result object, based 921 * on the current OutputProperties. 922 * 923 * @param outputTarget Where the transform result should go, 924 * should not be null. 925 * 926 * @return A valid ContentHandler that will create the 927 * result tree when it is fed SAX events. 928 * 929 * @throws TransformerException 930 */ createSerializationHandler(Result outputTarget)931 public SerializationHandler createSerializationHandler(Result outputTarget) 932 throws TransformerException 933 { 934 SerializationHandler xoh = 935 createSerializationHandler(outputTarget, getOutputFormat()); 936 return xoh; 937 } 938 939 /** 940 * Create a ContentHandler from a Result object and an OutputProperties. 941 * 942 * @param outputTarget Where the transform result should go, 943 * should not be null. 944 * @param format The OutputProperties object that will contain 945 * instructions on how to serialize the output. 946 * 947 * @return A valid ContentHandler that will create the 948 * result tree when it is fed SAX events. 949 * 950 * @throws TransformerException 951 */ createSerializationHandler( Result outputTarget, OutputProperties format)952 public SerializationHandler createSerializationHandler( 953 Result outputTarget, OutputProperties format) 954 throws TransformerException 955 { 956 957 SerializationHandler xoh; 958 959 // If the Result object contains a Node, then create 960 // a ContentHandler that will add nodes to the input node. 961 org.w3c.dom.Node outputNode = null; 962 963 if (outputTarget instanceof DOMResult) 964 { 965 outputNode = ((DOMResult) outputTarget).getNode(); 966 org.w3c.dom.Node nextSibling = ((DOMResult)outputTarget).getNextSibling(); 967 968 org.w3c.dom.Document doc; 969 short type; 970 971 if (null != outputNode) 972 { 973 type = outputNode.getNodeType(); 974 doc = (org.w3c.dom.Node.DOCUMENT_NODE == type) 975 ? (org.w3c.dom.Document) outputNode 976 : outputNode.getOwnerDocument(); 977 } 978 else 979 { 980 boolean isSecureProcessing = m_stylesheetRoot.isSecureProcessing(); 981 doc = org.apache.xml.utils.DOMHelper.createDocument(isSecureProcessing); 982 outputNode = doc; 983 type = outputNode.getNodeType(); 984 985 ((DOMResult) outputTarget).setNode(outputNode); 986 } 987 988 DOMBuilder handler = 989 (org.w3c.dom.Node.DOCUMENT_FRAGMENT_NODE == type) 990 ? new DOMBuilder(doc, (org.w3c.dom.DocumentFragment) outputNode) 991 : new DOMBuilder(doc, outputNode); 992 993 if (nextSibling != null) 994 handler.setNextSibling(nextSibling); 995 996 String encoding = format.getProperty(OutputKeys.ENCODING); 997 xoh = new ToXMLSAXHandler(handler, (LexicalHandler)handler, encoding); 998 } 999 else if (outputTarget instanceof SAXResult) 1000 { 1001 ContentHandler handler = ((SAXResult) outputTarget).getHandler(); 1002 1003 if (null == handler) 1004 throw new IllegalArgumentException( 1005 "handler can not be null for a SAXResult"); 1006 1007 LexicalHandler lexHandler; 1008 if (handler instanceof LexicalHandler) 1009 lexHandler = (LexicalHandler) handler; 1010 else 1011 lexHandler = null; 1012 1013 String encoding = format.getProperty(OutputKeys.ENCODING); 1014 String method = format.getProperty(OutputKeys.METHOD); 1015 1016 ToXMLSAXHandler toXMLSAXHandler = new ToXMLSAXHandler(handler, lexHandler, encoding); 1017 toXMLSAXHandler.setShouldOutputNSAttr(false); 1018 xoh = toXMLSAXHandler; 1019 1020 1021 String publicID = format.getProperty(OutputKeys.DOCTYPE_PUBLIC); 1022 String systemID = format.getProperty(OutputKeys.DOCTYPE_SYSTEM); 1023 if (systemID != null) 1024 xoh.setDoctypeSystem(systemID); 1025 if (publicID != null) 1026 xoh.setDoctypePublic(publicID); 1027 1028 if (handler instanceof TransformerClient) { 1029 XalanTransformState state = new XalanTransformState(); 1030 ((TransformerClient)handler).setTransformState(state); 1031 ((ToSAXHandler)xoh).setTransformState(state); 1032 } 1033 1034 1035 } 1036 1037 // Otherwise, create a ContentHandler that will serialize the 1038 // result tree to either a stream or a writer. 1039 else if (outputTarget instanceof StreamResult) 1040 { 1041 StreamResult sresult = (StreamResult) outputTarget; 1042 1043 try 1044 { 1045 SerializationHandler serializer = 1046 (SerializationHandler) SerializerFactory.getSerializer(format.getProperties()); 1047 1048 if (null != sresult.getWriter()) 1049 serializer.setWriter(sresult.getWriter()); 1050 else if (null != sresult.getOutputStream()) 1051 serializer.setOutputStream(sresult.getOutputStream()); 1052 else if (null != sresult.getSystemId()) 1053 { 1054 String fileURL = sresult.getSystemId(); 1055 1056 if (fileURL.startsWith("file:///")) 1057 { 1058 if (fileURL.substring(8).indexOf(":") >0) 1059 fileURL = fileURL.substring(8); 1060 else 1061 fileURL = fileURL.substring(7); 1062 } 1063 else if (fileURL.startsWith("file:/")) 1064 { 1065 if (fileURL.substring(6).indexOf(":") >0) 1066 fileURL = fileURL.substring(6); 1067 else 1068 fileURL = fileURL.substring(5); 1069 } 1070 1071 m_outputStream = new java.io.FileOutputStream(fileURL); 1072 1073 serializer.setOutputStream(m_outputStream); 1074 1075 xoh = serializer; 1076 } 1077 else 1078 throw new TransformerException(XSLMessages.createMessage(XSLTErrorResources.ER_NO_OUTPUT_SPECIFIED, null)); //"No output specified!"); 1079 1080 // handler = serializer.asContentHandler(); 1081 1082 // this.setSerializer(serializer); 1083 1084 xoh = serializer; 1085 } 1086 // catch (UnsupportedEncodingException uee) 1087 // { 1088 // throw new TransformerException(uee); 1089 // } 1090 catch (IOException ioe) 1091 { 1092 throw new TransformerException(ioe); 1093 } 1094 } 1095 else 1096 { 1097 throw new TransformerException(XSLMessages.createMessage(XSLTErrorResources.ER_CANNOT_TRANSFORM_TO_RESULT_TYPE, new Object[]{outputTarget.getClass().getName()})); //"Can't transform to a Result of type " 1098 //+ outputTarget.getClass().getName() 1099 //+ "!"); 1100 } 1101 1102 // before we forget, lets make the created handler hold a reference 1103 // to the current TransformImpl object 1104 xoh.setTransformer(this); 1105 1106 SourceLocator srcLocator = getStylesheet(); 1107 xoh.setSourceLocator(srcLocator); 1108 1109 1110 return xoh; 1111 1112 1113 } 1114 1115 /** 1116 * Process the source tree to the output result. 1117 * @param xmlSource The input for the source tree. 1118 * @param outputTarget The output source target. 1119 * 1120 * @throws TransformerException 1121 */ transform(Source xmlSource, Result outputTarget)1122 public void transform(Source xmlSource, Result outputTarget) 1123 throws TransformerException 1124 { 1125 transform(xmlSource, outputTarget, true); 1126 } 1127 1128 /** 1129 * Process the source tree to the output result. 1130 * @param xmlSource The input for the source tree. 1131 * @param outputTarget The output source target. 1132 * @param shouldRelease Flag indicating whether to release DTMManager. 1133 * 1134 * @throws TransformerException 1135 */ transform(Source xmlSource, Result outputTarget, boolean shouldRelease)1136 public void transform(Source xmlSource, Result outputTarget, boolean shouldRelease) 1137 throws TransformerException 1138 { 1139 1140 synchronized (m_reentryGuard) 1141 { 1142 SerializationHandler xoh = createSerializationHandler(outputTarget); 1143 this.setSerializationHandler(xoh); 1144 1145 m_outputTarget = outputTarget; 1146 1147 transform(xmlSource, shouldRelease); 1148 } 1149 } 1150 1151 /** 1152 * Process the source node to the output result, if the 1153 * processor supports the "http://xml.org/trax/features/dom/input" 1154 * feature. 1155 * %REVIEW% Do we need a Node version of this? 1156 * @param node The input source node, which can be any valid DTM node. 1157 * @param outputTarget The output source target. 1158 * 1159 * @throws TransformerException 1160 */ transformNode(int node, Result outputTarget)1161 public void transformNode(int node, Result outputTarget) 1162 throws TransformerException 1163 { 1164 1165 1166 SerializationHandler xoh = createSerializationHandler(outputTarget); 1167 this.setSerializationHandler(xoh); 1168 1169 m_outputTarget = outputTarget; 1170 1171 transformNode(node); 1172 } 1173 1174 /** 1175 * Process the source node to the output result, if the 1176 * processor supports the "http://xml.org/trax/features/dom/input" 1177 * feature. 1178 * %REVIEW% Do we need a Node version of this? 1179 * @param node The input source node, which can be any valid DTM node. 1180 * 1181 * @throws TransformerException 1182 */ transformNode(int node)1183 public void transformNode(int node) throws TransformerException 1184 { 1185 //dml 1186 setExtensionsTable(getStylesheet()); 1187 // Make sure we're not writing to the same output content handler. 1188 synchronized (m_serializationHandler) 1189 { 1190 m_hasBeenReset = false; 1191 1192 XPathContext xctxt = getXPathContext(); 1193 DTM dtm = xctxt.getDTM(node); 1194 1195 try 1196 { 1197 pushGlobalVars(node); 1198 1199 // ========== 1200 // Give the top-level templates a chance to pass information into 1201 // the context (this is mainly for setting up tables for extensions). 1202 StylesheetRoot stylesheet = this.getStylesheet(); 1203 int n = stylesheet.getGlobalImportCount(); 1204 1205 for (int i = 0; i < n; i++) 1206 { 1207 StylesheetComposed imported = stylesheet.getGlobalImport(i); 1208 int includedCount = imported.getIncludeCountComposed(); 1209 1210 for (int j = -1; j < includedCount; j++) 1211 { 1212 Stylesheet included = imported.getIncludeComposed(j); 1213 1214 included.runtimeInit(this); 1215 1216 for (ElemTemplateElement child = included.getFirstChildElem(); 1217 child != null; child = child.getNextSiblingElem()) 1218 { 1219 child.runtimeInit(this); 1220 } 1221 } 1222 } 1223 // =========== 1224 // System.out.println("Calling applyTemplateToNode - "+Thread.currentThread().getName()); 1225 DTMIterator dtmIter = new org.apache.xpath.axes.SelfIteratorNoPredicate(); 1226 dtmIter.setRoot(node, xctxt); 1227 xctxt.pushContextNodeList(dtmIter); 1228 try 1229 { 1230 this.applyTemplateToNode(null, null, node); 1231 } 1232 finally 1233 { 1234 xctxt.popContextNodeList(); 1235 } 1236 // m_stylesheetRoot.getStartRule().execute(this); 1237 1238 // System.out.println("Done with applyTemplateToNode - "+Thread.currentThread().getName()); 1239 if (null != m_serializationHandler) 1240 { 1241 m_serializationHandler.endDocument(); 1242 } 1243 } 1244 catch (Exception se) 1245 { 1246 1247 // System.out.println(Thread.currentThread().getName()+" threw an exception! " 1248 // +se.getMessage()); 1249 // If an exception was thrown, we need to make sure that any waiting 1250 // handlers can terminate, which I guess is best done by sending 1251 // an endDocument. 1252 1253 // SAXSourceLocator 1254 while(se instanceof org.apache.xml.utils.WrappedRuntimeException) 1255 { 1256 Exception e = ((org.apache.xml.utils.WrappedRuntimeException)se).getException(); 1257 if(null != e) 1258 se = e; 1259 } 1260 1261 if (null != m_serializationHandler) 1262 { 1263 try 1264 { 1265 if(se instanceof org.xml.sax.SAXParseException) 1266 m_serializationHandler.fatalError((org.xml.sax.SAXParseException)se); 1267 else if(se instanceof TransformerException) 1268 { 1269 TransformerException te = ((TransformerException)se); 1270 SAXSourceLocator sl = new SAXSourceLocator( te.getLocator() ); 1271 m_serializationHandler.fatalError(new org.xml.sax.SAXParseException(te.getMessage(), sl, te)); 1272 } 1273 else 1274 { 1275 m_serializationHandler.fatalError(new org.xml.sax.SAXParseException(se.getMessage(), new SAXSourceLocator(), se)); 1276 } 1277 } 1278 catch (Exception e){} 1279 } 1280 1281 if(se instanceof TransformerException) 1282 { 1283 m_errorHandler.fatalError((TransformerException)se); 1284 } 1285 else if(se instanceof org.xml.sax.SAXParseException) 1286 { 1287 m_errorHandler.fatalError(new TransformerException(se.getMessage(), 1288 new SAXSourceLocator((org.xml.sax.SAXParseException)se), 1289 se)); 1290 } 1291 else 1292 { 1293 m_errorHandler.fatalError(new TransformerException(se)); 1294 } 1295 1296 } 1297 finally 1298 { 1299 this.reset(); 1300 } 1301 } 1302 } 1303 1304 /** 1305 * Get a SAX2 ContentHandler for the input. 1306 * 1307 * @return A valid ContentHandler, which should never be null, as 1308 * long as getFeature("http://xml.org/trax/features/sax/input") 1309 * returns true. 1310 */ getInputContentHandler()1311 public ContentHandler getInputContentHandler() 1312 { 1313 return getInputContentHandler(false); 1314 } 1315 1316 /** 1317 * Get a SAX2 ContentHandler for the input. 1318 * 1319 * @param doDocFrag true if a DocumentFragment should be created as 1320 * the root, rather than a Document. 1321 * 1322 * @return A valid ContentHandler, which should never be null, as 1323 * long as getFeature("http://xml.org/trax/features/sax/input") 1324 * returns true. 1325 */ getInputContentHandler(boolean doDocFrag)1326 public ContentHandler getInputContentHandler(boolean doDocFrag) 1327 { 1328 1329 if (null == m_inputContentHandler) 1330 { 1331 1332 // if(null == m_urlOfSource && null != m_stylesheetRoot) 1333 // m_urlOfSource = m_stylesheetRoot.getBaseIdentifier(); 1334 m_inputContentHandler = new TransformerHandlerImpl(this, doDocFrag, 1335 m_urlOfSource); 1336 } 1337 1338 return m_inputContentHandler; 1339 } 1340 1341 /** 1342 * Set the output properties for the transformation. These 1343 * properties will override properties set in the templates 1344 * with xsl:output. 1345 * 1346 * @param oformat A valid OutputProperties object (which will 1347 * not be mutated), or null. 1348 */ setOutputFormat(OutputProperties oformat)1349 public void setOutputFormat(OutputProperties oformat) 1350 { 1351 m_outputFormat = oformat; 1352 } 1353 1354 /** 1355 * Get the output properties used for the transformation. 1356 * 1357 * @return the output format that was set by the user, 1358 * otherwise the output format from the stylesheet. 1359 */ getOutputFormat()1360 public OutputProperties getOutputFormat() 1361 { 1362 1363 // Get the output format that was set by the user, otherwise get the 1364 // output format from the stylesheet. 1365 OutputProperties format = (null == m_outputFormat) 1366 ? getStylesheet().getOutputComposed() 1367 : m_outputFormat; 1368 1369 return format; 1370 } 1371 1372 /** 1373 * Set a parameter for the templates. 1374 * 1375 * @param name The name of the parameter. 1376 * @param namespace The namespace of the parameter. 1377 * @param value The value object. This can be any valid Java object 1378 * -- it's up to the processor to provide the proper 1379 * coersion to the object, or simply pass it on for use 1380 * in extensions. 1381 */ setParameter(String name, String namespace, Object value)1382 public void setParameter(String name, String namespace, Object value) 1383 { 1384 1385 VariableStack varstack = getXPathContext().getVarStack(); 1386 QName qname = new QName(namespace, name); 1387 XObject xobject = XObject.create(value, getXPathContext()); 1388 1389 StylesheetRoot sroot = m_stylesheetRoot; 1390 Vector vars = sroot.getVariablesAndParamsComposed(); 1391 int i = vars.size(); 1392 while (--i >= 0) 1393 { 1394 ElemVariable variable = (ElemVariable)vars.elementAt(i); 1395 if(variable.getXSLToken() == Constants.ELEMNAME_PARAMVARIABLE && 1396 variable.getName().equals(qname)) 1397 { 1398 varstack.setGlobalVariable(i, xobject); 1399 } 1400 } 1401 } 1402 1403 /** NEEDSDOC Field m_userParams */ 1404 Vector m_userParams; 1405 1406 /** 1407 * Set a parameter for the transformation. 1408 * 1409 * @param name The name of the parameter, 1410 * which may have a namespace URI. 1411 * @param value The value object. This can be any valid Java object 1412 * -- it's up to the processor to provide the proper 1413 * coersion to the object, or simply pass it on for use 1414 * in extensions. 1415 */ setParameter(String name, Object value)1416 public void setParameter(String name, Object value) 1417 { 1418 1419 if (value == null) { 1420 throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_INVALID_SET_PARAM_VALUE, new Object[]{name})); 1421 } 1422 1423 StringTokenizer tokenizer = new StringTokenizer(name, "{}", false); 1424 1425 try 1426 { 1427 1428 // The first string might be the namespace, or it might be 1429 // the local name, if the namespace is null. 1430 String s1 = tokenizer.nextToken(); 1431 String s2 = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : null; 1432 1433 if (null == m_userParams) 1434 m_userParams = new Vector(); 1435 1436 if (null == s2) 1437 { 1438 replaceOrPushUserParam(new QName(s1), XObject.create(value, getXPathContext())); 1439 setParameter(s1, null, value); 1440 } 1441 else 1442 { 1443 replaceOrPushUserParam(new QName(s1, s2), XObject.create(value, getXPathContext())); 1444 setParameter(s2, s1, value); 1445 } 1446 } 1447 catch (java.util.NoSuchElementException nsee) 1448 { 1449 1450 // Should throw some sort of an error. 1451 } 1452 } 1453 1454 /** 1455 * NEEDSDOC Method replaceOrPushUserParam 1456 * 1457 * 1458 * NEEDSDOC @param qname 1459 * NEEDSDOC @param xval 1460 */ replaceOrPushUserParam(QName qname, XObject xval)1461 private void replaceOrPushUserParam(QName qname, XObject xval) 1462 { 1463 1464 int n = m_userParams.size(); 1465 1466 for (int i = n - 1; i >= 0; i--) 1467 { 1468 Arg arg = (Arg) m_userParams.elementAt(i); 1469 1470 if (arg.getQName().equals(qname)) 1471 { 1472 m_userParams.setElementAt(new Arg(qname, xval, true), i); 1473 1474 return; 1475 } 1476 } 1477 1478 m_userParams.addElement(new Arg(qname, xval, true)); 1479 } 1480 1481 /** 1482 * Get a parameter that was explicitly set with setParameter 1483 * or setParameters. 1484 * 1485 * 1486 * NEEDSDOC @param name 1487 * @return A parameter that has been set with setParameter 1488 * or setParameters, 1489 * *not* all the xsl:params on the stylesheet (which require 1490 * a transformation Source to be evaluated). 1491 */ getParameter(String name)1492 public Object getParameter(String name) 1493 { 1494 1495 try 1496 { 1497 1498 // VariableStack varstack = getXPathContext().getVarStack(); 1499 // The first string might be the namespace, or it might be 1500 // the local name, if the namespace is null. 1501 QName qname = QName.getQNameFromString(name); 1502 1503 if (null == m_userParams) 1504 return null; 1505 1506 int n = m_userParams.size(); 1507 1508 for (int i = n - 1; i >= 0; i--) 1509 { 1510 Arg arg = (Arg) m_userParams.elementAt(i); 1511 1512 if (arg.getQName().equals(qname)) 1513 { 1514 return arg.getVal().object(); 1515 } 1516 } 1517 1518 return null; 1519 } 1520 catch (java.util.NoSuchElementException nsee) 1521 { 1522 1523 // Should throw some sort of an error. 1524 return null; 1525 } 1526 } 1527 1528 /** 1529 * Reset parameters that the user specified for the transformation. 1530 * Called during transformer.reset() after we have cleared the 1531 * variable stack. We need to make sure that user params are 1532 * reset so that the transformer object can be reused. 1533 */ resetUserParameters()1534 private void resetUserParameters() 1535 { 1536 1537 try 1538 { 1539 1540 if (null == m_userParams) 1541 return; 1542 1543 int n = m_userParams.size(); 1544 for (int i = n - 1; i >= 0; i--) 1545 { 1546 Arg arg = (Arg) m_userParams.elementAt(i); 1547 QName name = arg.getQName(); 1548 // The first string might be the namespace, or it might be 1549 // the local name, if the namespace is null. 1550 String s1 = name.getNamespace(); 1551 String s2 = name.getLocalPart(); 1552 1553 setParameter(s2, s1, arg.getVal().object()); 1554 1555 } 1556 1557 } 1558 catch (java.util.NoSuchElementException nsee) 1559 { 1560 // Should throw some sort of an error. 1561 1562 } 1563 } 1564 1565 /** 1566 * Set a bag of parameters for the transformation. Note that 1567 * these will not be additive, they will replace the existing 1568 * set of parameters. 1569 * 1570 * NEEDSDOC @param params 1571 */ setParameters(Properties params)1572 public void setParameters(Properties params) 1573 { 1574 1575 clearParameters(); 1576 1577 Enumeration names = params.propertyNames(); 1578 1579 while (names.hasMoreElements()) 1580 { 1581 String name = params.getProperty((String) names.nextElement()); 1582 StringTokenizer tokenizer = new StringTokenizer(name, "{}", false); 1583 1584 try 1585 { 1586 1587 // The first string might be the namespace, or it might be 1588 // the local name, if the namespace is null. 1589 String s1 = tokenizer.nextToken(); 1590 String s2 = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : null; 1591 1592 if (null == s2) 1593 setParameter(s1, null, params.getProperty(name)); 1594 else 1595 setParameter(s2, s1, params.getProperty(name)); 1596 } 1597 catch (java.util.NoSuchElementException nsee) 1598 { 1599 1600 // Should throw some sort of an error. 1601 } 1602 } 1603 } 1604 1605 /** 1606 * Reset the parameters to a null list. 1607 */ clearParameters()1608 public void clearParameters() 1609 { 1610 1611 synchronized (m_reentryGuard) 1612 { 1613 VariableStack varstack = new VariableStack(); 1614 1615 m_xcontext.setVarStack(varstack); 1616 1617 m_userParams = null; 1618 } 1619 } 1620 1621 1622 /** 1623 * Internal -- push the global variables from the Stylesheet onto 1624 * the context's runtime variable stack. 1625 * <p>If we encounter a variable 1626 * that is already defined in the variable stack, we ignore it. This 1627 * is because the second variable definition will be at a lower import 1628 * precedence. Presumably, global"variables at the same import precedence 1629 * with the same name will have been caught during the recompose process. 1630 * <p>However, if we encounter a parameter that is already defined in the 1631 * variable stack, we need to see if this is a parameter whose value was 1632 * supplied by a setParameter call. If so, we need to "receive" the one 1633 * already in the stack, ignoring this one. If it is just an earlier 1634 * xsl:param or xsl:variable definition, we ignore it using the same 1635 * reasoning as explained above for the variable. 1636 * 1637 * @param contextNode The root of the source tree, can't be null. 1638 * 1639 * @throws TransformerException 1640 */ pushGlobalVars(int contextNode)1641 protected void pushGlobalVars(int contextNode) throws TransformerException 1642 { 1643 1644 XPathContext xctxt = m_xcontext; 1645 VariableStack vs = xctxt.getVarStack(); 1646 StylesheetRoot sr = getStylesheet(); 1647 Vector vars = sr.getVariablesAndParamsComposed(); 1648 1649 int i = vars.size(); 1650 vs.link(i); 1651 1652 while (--i >= 0) 1653 { 1654 ElemVariable v = (ElemVariable) vars.elementAt(i); 1655 1656 // XObject xobj = v.getValue(this, contextNode); 1657 XObject xobj = new XUnresolvedVariable(v, contextNode, this, 1658 vs.getStackFrame(), 0, true); 1659 1660 if(null == vs.elementAt(i)) 1661 vs.setGlobalVariable(i, xobj); 1662 } 1663 1664 } 1665 1666 /** 1667 * Set an object that will be used to resolve URIs used in 1668 * document(), etc. 1669 * @param resolver An object that implements the URIResolver interface, 1670 * or null. 1671 */ setURIResolver(URIResolver resolver)1672 public void setURIResolver(URIResolver resolver) 1673 { 1674 1675 synchronized (m_reentryGuard) 1676 { 1677 m_xcontext.getSourceTreeManager().setURIResolver(resolver); 1678 } 1679 } 1680 1681 /** 1682 * Get an object that will be used to resolve URIs used in 1683 * document(), etc. 1684 * 1685 * @return An object that implements the URIResolver interface, 1686 * or null. 1687 */ getURIResolver()1688 public URIResolver getURIResolver() 1689 { 1690 return m_xcontext.getSourceTreeManager().getURIResolver(); 1691 } 1692 1693 // ======== End Transformer Implementation ======== 1694 1695 /** 1696 * Set the content event handler. 1697 * 1698 * NEEDSDOC @param handler 1699 * @throws java.lang.NullPointerException If the handler 1700 * is null. 1701 * @see org.xml.sax.XMLReader#setContentHandler 1702 */ setContentHandler(ContentHandler handler)1703 public void setContentHandler(ContentHandler handler) 1704 { 1705 1706 if (handler == null) 1707 { 1708 throw new NullPointerException(XSLMessages.createMessage(XSLTErrorResources.ER_NULL_CONTENT_HANDLER, null)); //"Null content handler"); 1709 } 1710 else 1711 { 1712 m_outputContentHandler = handler; 1713 1714 if (null == m_serializationHandler) 1715 { 1716 ToXMLSAXHandler h = new ToXMLSAXHandler(); 1717 h.setContentHandler(handler); 1718 h.setTransformer(this); 1719 1720 m_serializationHandler = h; 1721 } 1722 else 1723 m_serializationHandler.setContentHandler(handler); 1724 } 1725 } 1726 1727 /** 1728 * Get the content event handler. 1729 * 1730 * @return The current content handler, or null if none was set. 1731 * @see org.xml.sax.XMLReader#getContentHandler 1732 */ getContentHandler()1733 public ContentHandler getContentHandler() 1734 { 1735 return m_outputContentHandler; 1736 } 1737 1738 /** 1739 * Given a stylesheet element, create a result tree fragment from it's 1740 * contents. The fragment will be built within the shared RTF DTM system 1741 * used as a variable stack. 1742 * @param templateParent The template element that holds the fragment. 1743 * @return the NodeHandle for the root node of the resulting RTF. 1744 * 1745 * @throws TransformerException 1746 * @xsl.usage advanced 1747 */ transformToRTF(ElemTemplateElement templateParent)1748 public int transformToRTF(ElemTemplateElement templateParent) 1749 throws TransformerException 1750 { 1751 // Retrieve a DTM to contain the RTF. At this writing, this may be a 1752 // multi-document DTM (SAX2RTFDTM). 1753 DTM dtmFrag = m_xcontext.getRTFDTM(); 1754 return transformToRTF(templateParent,dtmFrag); 1755 } 1756 1757 /** 1758 * Given a stylesheet element, create a result tree fragment from it's 1759 * contents. The fragment will also use the shared DTM system, but will 1760 * obtain its space from the global variable pool rather than the dynamic 1761 * variable stack. This allows late binding of XUnresolvedVariables without 1762 * the risk that their content will be discarded when the variable stack 1763 * is popped. 1764 * 1765 * @param templateParent The template element that holds the fragment. 1766 * @return the NodeHandle for the root node of the resulting RTF. 1767 * 1768 * @throws TransformerException 1769 * @xsl.usage advanced 1770 */ transformToGlobalRTF(ElemTemplateElement templateParent)1771 public int transformToGlobalRTF(ElemTemplateElement templateParent) 1772 throws TransformerException 1773 { 1774 // Retrieve a DTM to contain the RTF. At this writing, this may be a 1775 // multi-document DTM (SAX2RTFDTM). 1776 DTM dtmFrag = m_xcontext.getGlobalRTFDTM(); 1777 return transformToRTF(templateParent,dtmFrag); 1778 } 1779 1780 /** 1781 * Given a stylesheet element, create a result tree fragment from it's 1782 * contents. 1783 * @param templateParent The template element that holds the fragment. 1784 * @param dtmFrag The DTM to write the RTF into 1785 * @return the NodeHandle for the root node of the resulting RTF. 1786 * 1787 * @throws TransformerException 1788 * @xsl.usage advanced 1789 */ transformToRTF(ElemTemplateElement templateParent,DTM dtmFrag)1790 private int transformToRTF(ElemTemplateElement templateParent,DTM dtmFrag) 1791 throws TransformerException 1792 { 1793 1794 XPathContext xctxt = m_xcontext; 1795 1796 ContentHandler rtfHandler = dtmFrag.getContentHandler(); 1797 1798 // Obtain the ResultTreeFrag's root node. 1799 // NOTE: In SAX2RTFDTM, this value isn't available until after 1800 // the startDocument has been issued, so assignment has been moved 1801 // down a bit in the code. 1802 int resultFragment; // not yet reliably = dtmFrag.getDocument(); 1803 1804 // Save the current result tree handler. 1805 SerializationHandler savedRTreeHandler = this.m_serializationHandler; 1806 1807 1808 // And make a new handler for the RTF. 1809 ToSAXHandler h = new ToXMLSAXHandler(); 1810 h.setContentHandler(rtfHandler); 1811 h.setTransformer(this); 1812 1813 // Replace the old handler (which was already saved) 1814 m_serializationHandler = h; 1815 1816 // use local variable for the current handler 1817 SerializationHandler rth = m_serializationHandler; 1818 1819 try 1820 { 1821 rth.startDocument(); 1822 1823 // startDocument is "bottlenecked" in RTH. We need it acted upon immediately, 1824 // to set the DTM's state as in-progress, so that if the xsl:variable's body causes 1825 // further RTF activity we can keep that from bashing this DTM. 1826 rth.flushPending(); 1827 1828 try 1829 { 1830 1831 // Do the transformation of the child elements. 1832 executeChildTemplates(templateParent, true); 1833 1834 // Make sure everything is flushed! 1835 rth.flushPending(); 1836 1837 // Get the document ID. May not exist until the RTH has not only 1838 // received, but flushed, the startDocument, and may be invalid 1839 // again after the document has been closed (still debating that) 1840 // ... so waiting until just before the end seems simplest/safest. 1841 resultFragment = dtmFrag.getDocument(); 1842 } 1843 finally 1844 { 1845 rth.endDocument(); 1846 } 1847 } 1848 catch (org.xml.sax.SAXException se) 1849 { 1850 throw new TransformerException(se); 1851 } 1852 finally 1853 { 1854 1855 // Restore the previous result tree handler. 1856 this.m_serializationHandler = savedRTreeHandler; 1857 } 1858 1859 return resultFragment; 1860 } 1861 1862 /** 1863 * Take the contents of a template element, process it, and 1864 * convert it to a string. 1865 * 1866 * @param elem The parent element whose children will be output 1867 * as a string. 1868 * 1869 * @return The stringized result of executing the elements children. 1870 * 1871 * @throws TransformerException 1872 * @xsl.usage advanced 1873 */ transformToString(ElemTemplateElement elem)1874 public String transformToString(ElemTemplateElement elem) 1875 throws TransformerException 1876 { 1877 ElemTemplateElement firstChild = elem.getFirstChildElem(); 1878 if(null == firstChild) 1879 return ""; 1880 if(elem.hasTextLitOnly() && m_optimizer) 1881 { 1882 return ((ElemTextLiteral)firstChild).getNodeValue(); 1883 } 1884 1885 // Save the current result tree handler. 1886 SerializationHandler savedRTreeHandler = this.m_serializationHandler; 1887 1888 // Create a Serializer object that will handle the SAX events 1889 // and build the ResultTreeFrag nodes. 1890 StringWriter sw = (StringWriter) m_stringWriterObjectPool.getInstance(); 1891 1892 m_serializationHandler = 1893 (ToTextStream) m_textResultHandlerObjectPool.getInstance(); 1894 1895 if (null == m_serializationHandler) 1896 { 1897 // if we didn't get one from the pool, go make a new one 1898 1899 1900 Serializer serializer = org.apache.xml.serializer.SerializerFactory.getSerializer( 1901 m_textformat.getProperties()); 1902 m_serializationHandler = (SerializationHandler) serializer; 1903 } 1904 1905 m_serializationHandler.setTransformer(this); 1906 m_serializationHandler.setWriter(sw); 1907 1908 1909 String result; 1910 1911 try 1912 { 1913 /* Don't call startDocument, the SerializationHandler will 1914 * generate its own internal startDocument call anyways 1915 */ 1916 // this.m_serializationHandler.startDocument(); 1917 1918 // Do the transformation of the child elements. 1919 executeChildTemplates(elem, true); 1920 this.m_serializationHandler.endDocument(); 1921 1922 result = sw.toString(); 1923 } 1924 catch (org.xml.sax.SAXException se) 1925 { 1926 throw new TransformerException(se); 1927 } 1928 finally 1929 { 1930 sw.getBuffer().setLength(0); 1931 1932 try 1933 { 1934 sw.close(); 1935 } 1936 catch (Exception ioe){} 1937 1938 m_stringWriterObjectPool.freeInstance(sw); 1939 m_serializationHandler.reset(); 1940 m_textResultHandlerObjectPool.freeInstance(m_serializationHandler); 1941 1942 // Restore the previous result tree handler. 1943 m_serializationHandler = savedRTreeHandler; 1944 } 1945 1946 return result; 1947 } 1948 1949 /** 1950 * Given an element and mode, find the corresponding 1951 * template and process the contents. 1952 * 1953 * @param xslInstruction The calling element. 1954 * @param template The template to use if xsl:for-each, current template for apply-imports, or null. 1955 * @param child The source context node. 1956 * @throws TransformerException 1957 * @return true if applied a template, false if not. 1958 * @xsl.usage advanced 1959 */ applyTemplateToNode(ElemTemplateElement xslInstruction, ElemTemplate template, int child)1960 public boolean applyTemplateToNode(ElemTemplateElement xslInstruction, // xsl:apply-templates or xsl:for-each 1961 ElemTemplate template, int child) 1962 throws TransformerException 1963 { 1964 1965 DTM dtm = m_xcontext.getDTM(child); 1966 short nodeType = dtm.getNodeType(child); 1967 boolean isDefaultTextRule = false; 1968 boolean isApplyImports = false; 1969 1970 isApplyImports = ((xslInstruction == null) 1971 ? false 1972 : xslInstruction.getXSLToken() 1973 == Constants.ELEMNAME_APPLY_IMPORTS); 1974 1975 if (null == template || isApplyImports) 1976 { 1977 int maxImportLevel, endImportLevel=0; 1978 1979 if (isApplyImports) 1980 { 1981 maxImportLevel = 1982 template.getStylesheetComposed().getImportCountComposed() - 1; 1983 endImportLevel = 1984 template.getStylesheetComposed().getEndImportCountComposed(); 1985 } 1986 else 1987 { 1988 maxImportLevel = -1; 1989 } 1990 1991 // If we're trying an xsl:apply-imports at the top level (ie there are no 1992 // imported stylesheets), we need to indicate that there is no matching template. 1993 // The above logic will calculate a maxImportLevel of -1 which indicates 1994 // that we should find any template. This is because a value of -1 for 1995 // maxImportLevel has a special meaning. But we don't want that. 1996 // We want to match -no- templates. See bugzilla bug 1170. 1997 if (isApplyImports && (maxImportLevel == -1)) 1998 { 1999 template = null; 2000 } 2001 else 2002 { 2003 2004 // Find the XSL template that is the best match for the 2005 // element. 2006 XPathContext xctxt = m_xcontext; 2007 2008 try 2009 { 2010 xctxt.pushNamespaceContext(xslInstruction); 2011 2012 QName mode = this.getMode(); 2013 2014 if (isApplyImports) 2015 template = m_stylesheetRoot.getTemplateComposed(xctxt, child, mode, 2016 maxImportLevel, endImportLevel, m_quietConflictWarnings, dtm); 2017 else 2018 template = m_stylesheetRoot.getTemplateComposed(xctxt, child, mode, 2019 m_quietConflictWarnings, dtm); 2020 2021 } 2022 finally 2023 { 2024 xctxt.popNamespaceContext(); 2025 } 2026 } 2027 2028 // If that didn't locate a node, fall back to a default template rule. 2029 // See http://www.w3.org/TR/xslt#built-in-rule. 2030 if (null == template) 2031 { 2032 switch (nodeType) 2033 { 2034 case DTM.DOCUMENT_FRAGMENT_NODE : 2035 case DTM.ELEMENT_NODE : 2036 template = m_stylesheetRoot.getDefaultRule(); 2037 break; 2038 case DTM.CDATA_SECTION_NODE : 2039 case DTM.TEXT_NODE : 2040 case DTM.ATTRIBUTE_NODE : 2041 template = m_stylesheetRoot.getDefaultTextRule(); 2042 isDefaultTextRule = true; 2043 break; 2044 case DTM.DOCUMENT_NODE : 2045 template = m_stylesheetRoot.getDefaultRootRule(); 2046 break; 2047 default : 2048 2049 // No default rules for processing instructions and the like. 2050 return false; 2051 } 2052 } 2053 } 2054 2055 // If we are processing the default text rule, then just clone 2056 // the value directly to the result tree. 2057 try 2058 { 2059 pushElemTemplateElement(template); 2060 m_xcontext.pushCurrentNode(child); 2061 pushPairCurrentMatched(template, child); 2062 2063 // Fix copy copy29 test. 2064 if (!isApplyImports) { 2065 DTMIterator cnl = new org.apache.xpath.NodeSetDTM(child, m_xcontext.getDTMManager()); 2066 m_xcontext.pushContextNodeList(cnl); 2067 } 2068 2069 if (isDefaultTextRule) 2070 { 2071 switch (nodeType) 2072 { 2073 case DTM.CDATA_SECTION_NODE : 2074 case DTM.TEXT_NODE : 2075 ClonerToResultTree.cloneToResultTree(child, nodeType, 2076 dtm, getResultTreeHandler(), false); 2077 break; 2078 case DTM.ATTRIBUTE_NODE : 2079 dtm.dispatchCharactersEvents(child, getResultTreeHandler(), false); 2080 break; 2081 } 2082 } 2083 else 2084 { 2085 2086 // And execute the child templates. 2087 // 9/11/00: If template has been compiled, hand off to it 2088 // since much (most? all?) of the processing has been inlined. 2089 // (It would be nice if there was a single entry point that 2090 // worked for both... but the interpretive system works by 2091 // having the Tranformer execute the children, while the 2092 // compiled obviously has to run its own code. It's 2093 // also unclear that "execute" is really the right name for 2094 // that entry point.) 2095 m_xcontext.setSAXLocator(template); 2096 // m_xcontext.getVarStack().link(); 2097 m_xcontext.getVarStack().link(template.m_frameSize); 2098 executeChildTemplates(template, true); 2099 } 2100 } 2101 catch (org.xml.sax.SAXException se) 2102 { 2103 throw new TransformerException(se); 2104 } 2105 finally 2106 { 2107 if (!isDefaultTextRule) 2108 m_xcontext.getVarStack().unlink(); 2109 m_xcontext.popCurrentNode(); 2110 if (!isApplyImports) { 2111 m_xcontext.popContextNodeList(); 2112 } 2113 popCurrentMatched(); 2114 2115 popElemTemplateElement(); 2116 } 2117 2118 return true; 2119 } 2120 2121 2122 /** 2123 * Execute each of the children of a template element. This method 2124 * is only for extension use. 2125 * 2126 * @param elem The ElemTemplateElement that contains the children 2127 * that should execute. 2128 * NEEDSDOC @param context 2129 * @param mode The current mode. 2130 * @param handler The ContentHandler to where the result events 2131 * should be fed. 2132 * 2133 * @throws TransformerException 2134 * @xsl.usage advanced 2135 */ executeChildTemplates( ElemTemplateElement elem, org.w3c.dom.Node context, QName mode, ContentHandler handler)2136 public void executeChildTemplates( 2137 ElemTemplateElement elem, org.w3c.dom.Node context, QName mode, ContentHandler handler) 2138 throws TransformerException 2139 { 2140 2141 XPathContext xctxt = m_xcontext; 2142 2143 try 2144 { 2145 if(null != mode) 2146 pushMode(mode); 2147 xctxt.pushCurrentNode(xctxt.getDTMHandleFromNode(context)); 2148 executeChildTemplates(elem, handler); 2149 } 2150 finally 2151 { 2152 xctxt.popCurrentNode(); 2153 2154 // I'm not sure where or why this was here. It is clearly in 2155 // error though, without a corresponding pushMode(). 2156 if (null != mode) 2157 popMode(); 2158 } 2159 } 2160 2161 /** 2162 * Execute each of the children of a template element. 2163 * 2164 * @param elem The ElemTemplateElement that contains the children 2165 * that should execute. 2166 * @param shouldAddAttrs true if xsl:attributes should be executed. 2167 * 2168 * @throws TransformerException 2169 * @xsl.usage advanced 2170 */ executeChildTemplates( ElemTemplateElement elem, boolean shouldAddAttrs)2171 public void executeChildTemplates( 2172 ElemTemplateElement elem, boolean shouldAddAttrs) 2173 throws TransformerException 2174 { 2175 2176 // Does this element have any children? 2177 ElemTemplateElement t = elem.getFirstChildElem(); 2178 2179 if (null == t) 2180 return; 2181 2182 if(elem.hasTextLitOnly() && m_optimizer) 2183 { 2184 char[] chars = ((ElemTextLiteral)t).getChars(); 2185 try 2186 { 2187 // Have to push stuff on for tooling... 2188 this.pushElemTemplateElement(t); 2189 m_serializationHandler.characters(chars, 0, chars.length); 2190 } 2191 catch(SAXException se) 2192 { 2193 throw new TransformerException(se); 2194 } 2195 finally 2196 { 2197 this.popElemTemplateElement(); 2198 } 2199 return; 2200 } 2201 2202 // // Check for infinite loops if we have to. 2203 // boolean check = (m_stackGuard.m_recursionLimit > -1); 2204 // 2205 // if (check) 2206 // getStackGuard().push(elem, xctxt.getCurrentNode()); 2207 2208 XPathContext xctxt = m_xcontext; 2209 xctxt.pushSAXLocatorNull(); 2210 int currentTemplateElementsTop = m_currentTemplateElements.size(); 2211 m_currentTemplateElements.push(null); 2212 2213 try 2214 { 2215 // Loop through the children of the template, calling execute on 2216 // each of them. 2217 for (; t != null; t = t.getNextSiblingElem()) 2218 { 2219 if (!shouldAddAttrs 2220 && t.getXSLToken() == Constants.ELEMNAME_ATTRIBUTE) 2221 continue; 2222 2223 xctxt.setSAXLocator(t); 2224 m_currentTemplateElements.setElementAt(t,currentTemplateElementsTop); 2225 t.execute(this); 2226 } 2227 } 2228 catch(RuntimeException re) 2229 { 2230 TransformerException te = new TransformerException(re); 2231 te.setLocator(t); 2232 throw te; 2233 } 2234 finally 2235 { 2236 m_currentTemplateElements.pop(); 2237 xctxt.popSAXLocator(); 2238 } 2239 2240 // Check for infinite loops if we have to 2241 // if (check) 2242 // getStackGuard().pop(); 2243 } 2244 /** 2245 * Execute each of the children of a template element. 2246 * 2247 * @param elem The ElemTemplateElement that contains the children 2248 * that should execute. 2249 * @param handler The ContentHandler to where the result events 2250 * should be fed. 2251 * 2252 * @throws TransformerException 2253 * @xsl.usage advanced 2254 */ executeChildTemplates( ElemTemplateElement elem, ContentHandler handler)2255 public void executeChildTemplates( 2256 ElemTemplateElement elem, ContentHandler handler) 2257 throws TransformerException 2258 { 2259 2260 SerializationHandler xoh = this.getSerializationHandler(); 2261 2262 // These may well not be the same! In this case when calling 2263 // the Redirect extension, it has already set the ContentHandler 2264 // in the Transformer. 2265 SerializationHandler savedHandler = xoh; 2266 2267 try 2268 { 2269 xoh.flushPending(); 2270 2271 // %REVIEW% Make sure current node is being pushed. 2272 LexicalHandler lex = null; 2273 if (handler instanceof LexicalHandler) { 2274 lex = (LexicalHandler) handler; 2275 } 2276 m_serializationHandler = new ToXMLSAXHandler(handler, lex, savedHandler.getEncoding()); 2277 m_serializationHandler.setTransformer(this); 2278 executeChildTemplates(elem, true); 2279 } 2280 catch (TransformerException e) 2281 { 2282 throw e; 2283 } 2284 catch (SAXException se) { 2285 throw new TransformerException(se); 2286 } 2287 finally 2288 { 2289 m_serializationHandler = savedHandler; 2290 } 2291 } 2292 2293 /** 2294 * Get the keys for the xsl:sort elements. 2295 * Note: Should this go into ElemForEach? 2296 * 2297 * @param foreach Valid ElemForEach element, not null. 2298 * @param sourceNodeContext The current node context in the source tree, 2299 * needed to evaluate the Attribute Value Templates. 2300 * 2301 * @return A Vector of NodeSortKeys, or null. 2302 * 2303 * @throws TransformerException 2304 * @xsl.usage advanced 2305 */ processSortKeys(ElemForEach foreach, int sourceNodeContext)2306 public Vector processSortKeys(ElemForEach foreach, int sourceNodeContext) 2307 throws TransformerException 2308 { 2309 2310 Vector keys = null; 2311 XPathContext xctxt = m_xcontext; 2312 int nElems = foreach.getSortElemCount(); 2313 2314 if (nElems > 0) 2315 keys = new Vector(); 2316 2317 // March backwards, collecting the sort keys. 2318 for (int i = 0; i < nElems; i++) 2319 { 2320 ElemSort sort = foreach.getSortElem(i); 2321 2322 String langString = 2323 (null != sort.getLang()) 2324 ? sort.getLang().evaluate(xctxt, sourceNodeContext, foreach) : null; 2325 String dataTypeString = sort.getDataType().evaluate(xctxt, 2326 sourceNodeContext, foreach); 2327 2328 if (dataTypeString.indexOf(":") >= 0) 2329 System.out.println( 2330 "TODO: Need to write the hooks for QNAME sort data type"); 2331 else if (!(dataTypeString.equalsIgnoreCase(Constants.ATTRVAL_DATATYPE_TEXT)) 2332 &&!(dataTypeString.equalsIgnoreCase( 2333 Constants.ATTRVAL_DATATYPE_NUMBER))) 2334 foreach.error(XSLTErrorResources.ER_ILLEGAL_ATTRIBUTE_VALUE, 2335 new Object[]{ Constants.ATTRNAME_DATATYPE, 2336 dataTypeString }); 2337 2338 boolean treatAsNumbers = 2339 ((null != dataTypeString) && dataTypeString.equals( 2340 Constants.ATTRVAL_DATATYPE_NUMBER)) ? true : false; 2341 String orderString = sort.getOrder().evaluate(xctxt, sourceNodeContext, 2342 foreach); 2343 2344 if (!(orderString.equalsIgnoreCase(Constants.ATTRVAL_ORDER_ASCENDING)) 2345 &&!(orderString.equalsIgnoreCase( 2346 Constants.ATTRVAL_ORDER_DESCENDING))) 2347 foreach.error(XSLTErrorResources.ER_ILLEGAL_ATTRIBUTE_VALUE, 2348 new Object[]{ Constants.ATTRNAME_ORDER, 2349 orderString }); 2350 2351 boolean descending = 2352 ((null != orderString) && orderString.equals( 2353 Constants.ATTRVAL_ORDER_DESCENDING)) ? true : false; 2354 AVT caseOrder = sort.getCaseOrder(); 2355 boolean caseOrderUpper; 2356 2357 if (null != caseOrder) 2358 { 2359 String caseOrderString = caseOrder.evaluate(xctxt, sourceNodeContext, 2360 foreach); 2361 2362 if (!(caseOrderString.equalsIgnoreCase(Constants.ATTRVAL_CASEORDER_UPPER)) 2363 &&!(caseOrderString.equalsIgnoreCase( 2364 Constants.ATTRVAL_CASEORDER_LOWER))) 2365 foreach.error(XSLTErrorResources.ER_ILLEGAL_ATTRIBUTE_VALUE, 2366 new Object[]{ Constants.ATTRNAME_CASEORDER, 2367 caseOrderString }); 2368 2369 caseOrderUpper = 2370 ((null != caseOrderString) && caseOrderString.equals( 2371 Constants.ATTRVAL_CASEORDER_UPPER)) ? true : false; 2372 } 2373 else 2374 { 2375 caseOrderUpper = false; 2376 } 2377 2378 keys.addElement(new NodeSortKey(this, sort.getSelect(), treatAsNumbers, 2379 descending, langString, caseOrderUpper, 2380 foreach)); 2381 } 2382 2383 return keys; 2384 } 2385 2386 //========================================================== 2387 // SECTION: TransformState implementation 2388 //========================================================== 2389 2390 /** 2391 * Get the count of how many elements are 2392 * active. 2393 * @return The number of active elements on 2394 * the currentTemplateElements stack. 2395 */ getCurrentTemplateElementsCount()2396 public int getCurrentTemplateElementsCount() 2397 { 2398 return m_currentTemplateElements.size(); 2399 } 2400 2401 2402 /** 2403 * Get the count of how many elements are 2404 * active. 2405 * @return The number of active elements on 2406 * the currentTemplateElements stack. 2407 */ getCurrentTemplateElements()2408 public ObjectStack getCurrentTemplateElements() 2409 { 2410 return m_currentTemplateElements; 2411 } 2412 2413 /** 2414 * Push the current template element. 2415 * 2416 * @param elem The current ElemTemplateElement (may be null, and then 2417 * set via setCurrentElement). 2418 */ pushElemTemplateElement(ElemTemplateElement elem)2419 public void pushElemTemplateElement(ElemTemplateElement elem) 2420 { 2421 m_currentTemplateElements.push(elem); 2422 } 2423 2424 /** 2425 * Pop the current template element. 2426 */ popElemTemplateElement()2427 public void popElemTemplateElement() 2428 { 2429 m_currentTemplateElements.pop(); 2430 } 2431 2432 /** 2433 * Set the top of the current template elements 2434 * stack. 2435 * 2436 * @param e The current ElemTemplateElement about to 2437 * be executed. 2438 */ setCurrentElement(ElemTemplateElement e)2439 public void setCurrentElement(ElemTemplateElement e) 2440 { 2441 m_currentTemplateElements.setTop(e); 2442 } 2443 2444 /** 2445 * Retrieves the current ElemTemplateElement that is 2446 * being executed. 2447 * 2448 * @return The current ElemTemplateElement that is executing, 2449 * should not normally be null. 2450 */ getCurrentElement()2451 public ElemTemplateElement getCurrentElement() 2452 { 2453 return (m_currentTemplateElements.size() > 0) ? 2454 (ElemTemplateElement) m_currentTemplateElements.peek() : null; 2455 } 2456 2457 /** 2458 * This method retrieves the current context node 2459 * in the source tree. 2460 * 2461 * @return The current context node (should never be null?). 2462 */ getCurrentNode()2463 public int getCurrentNode() 2464 { 2465 return m_xcontext.getCurrentNode(); 2466 } 2467 2468 /** 2469 * This method retrieves the xsl:template 2470 * that is in effect, which may be a matched template 2471 * or a named template. 2472 * 2473 * <p>Please note that the ElemTemplate returned may 2474 * be a default template, and thus may not have a template 2475 * defined in the stylesheet.</p> 2476 * 2477 * @return The current xsl:template, should not be null. 2478 */ getCurrentTemplate()2479 public ElemTemplate getCurrentTemplate() 2480 { 2481 2482 ElemTemplateElement elem = getCurrentElement(); 2483 2484 while ((null != elem) 2485 && (elem.getXSLToken() != Constants.ELEMNAME_TEMPLATE)) 2486 { 2487 elem = elem.getParentElem(); 2488 } 2489 2490 return (ElemTemplate) elem; 2491 } 2492 2493 /** 2494 * Push both the current xsl:template or xsl:for-each onto the 2495 * stack, along with the child node that was matched. 2496 * (Note: should this only be used for xsl:templates?? -sb) 2497 * 2498 * @param template xsl:template or xsl:for-each. 2499 * @param child The child that was matched. 2500 */ pushPairCurrentMatched(ElemTemplateElement template, int child)2501 public void pushPairCurrentMatched(ElemTemplateElement template, int child) 2502 { 2503 m_currentMatchTemplates.push(template); 2504 m_currentMatchedNodes.push(child); 2505 } 2506 2507 /** 2508 * Pop the elements that were pushed via pushPairCurrentMatched. 2509 */ popCurrentMatched()2510 public void popCurrentMatched() 2511 { 2512 m_currentMatchTemplates.pop(); 2513 m_currentMatchedNodes.pop(); 2514 } 2515 2516 /** 2517 * This method retrieves the xsl:template 2518 * that was matched. Note that this may not be 2519 * the same thing as the current template (which 2520 * may be from getCurrentElement()), since a named 2521 * template may be in effect. 2522 * 2523 * @return The pushed template that was pushed via pushPairCurrentMatched. 2524 */ getMatchedTemplate()2525 public ElemTemplate getMatchedTemplate() 2526 { 2527 return (ElemTemplate) m_currentMatchTemplates.peek(); 2528 } 2529 2530 /** 2531 * Retrieves the node in the source tree that matched 2532 * the template obtained via getMatchedTemplate(). 2533 * 2534 * @return The matched node that corresponds to the 2535 * match attribute of the current xsl:template. 2536 */ getMatchedNode()2537 public int getMatchedNode() 2538 { 2539 return m_currentMatchedNodes.peepTail(); 2540 } 2541 2542 /** 2543 * Get the current context node list. 2544 * 2545 * @return A reset clone of the context node list. 2546 */ getContextNodeList()2547 public DTMIterator getContextNodeList() 2548 { 2549 2550 try 2551 { 2552 DTMIterator cnl = m_xcontext.getContextNodeList(); 2553 2554 return (cnl == null) ? null : (DTMIterator) cnl.cloneWithReset(); 2555 } 2556 catch (CloneNotSupportedException cnse) 2557 { 2558 2559 // should never happen. 2560 return null; 2561 } 2562 } 2563 2564 /** 2565 * Get the TrAX Transformer object in effect. 2566 * 2567 * @return This object. 2568 */ getTransformer()2569 public Transformer getTransformer() 2570 { 2571 return this; 2572 } 2573 2574 //========================================================== 2575 // SECTION: Accessor Functions 2576 //========================================================== 2577 2578 /** 2579 * Set the stylesheet for this processor. If this is set, then the 2580 * process calls that take only the input .xml will use 2581 * this instead of looking for a stylesheet PI. Also, 2582 * setting the stylesheet is needed if you are going 2583 * to use the processor as a SAX ContentHandler. 2584 * 2585 * @param stylesheetRoot A non-null StylesheetRoot object, 2586 * or null if you wish to clear the stylesheet reference. 2587 */ setStylesheet(StylesheetRoot stylesheetRoot)2588 public void setStylesheet(StylesheetRoot stylesheetRoot) 2589 { 2590 m_stylesheetRoot = stylesheetRoot; 2591 } 2592 2593 /** 2594 * Get the current stylesheet for this processor. 2595 * 2596 * @return The stylesheet that is associated with this 2597 * transformer. 2598 */ getStylesheet()2599 public final StylesheetRoot getStylesheet() 2600 { 2601 return m_stylesheetRoot; 2602 } 2603 2604 /** 2605 * Get quietConflictWarnings property. If the quietConflictWarnings 2606 * property is set to true, warnings about pattern conflicts won't be 2607 * printed to the diagnostics stream. 2608 * 2609 * @return True if this transformer should not report 2610 * template match conflicts. 2611 */ getQuietConflictWarnings()2612 public boolean getQuietConflictWarnings() 2613 { 2614 return m_quietConflictWarnings; 2615 } 2616 2617 /** 2618 * Set the execution context for XPath. 2619 * 2620 * @param xcontext A non-null reference to the XPathContext 2621 * associated with this transformer. 2622 * @xsl.usage internal 2623 */ setXPathContext(XPathContext xcontext)2624 public void setXPathContext(XPathContext xcontext) 2625 { 2626 m_xcontext = xcontext; 2627 } 2628 2629 /** 2630 * Get the XPath context associated with this transformer. 2631 * 2632 * @return The XPathContext reference, never null. 2633 */ getXPathContext()2634 public final XPathContext getXPathContext() 2635 { 2636 return m_xcontext; 2637 } 2638 2639 /** 2640 * Get the SerializationHandler object. 2641 * 2642 * @return The current SerializationHandler, which may not 2643 * be the main result tree manager. 2644 */ getResultTreeHandler()2645 public SerializationHandler getResultTreeHandler() 2646 { 2647 return m_serializationHandler; 2648 } 2649 2650 /** 2651 * Get the SerializationHandler object. 2652 * 2653 * @return The current SerializationHandler, which may not 2654 * be the main result tree manager. 2655 */ getSerializationHandler()2656 public SerializationHandler getSerializationHandler() 2657 { 2658 return m_serializationHandler; 2659 } 2660 2661 /** 2662 * Get the KeyManager object. 2663 * 2664 * @return A reference to the KeyManager object, which should 2665 * never be null. 2666 */ getKeyManager()2667 public KeyManager getKeyManager() 2668 { 2669 return m_keyManager; 2670 } 2671 2672 /** 2673 * Check to see if this is a recursive attribute definition. 2674 * 2675 * @param attrSet A non-null ElemAttributeSet reference. 2676 * 2677 * @return true if the attribute set is recursive. 2678 */ isRecursiveAttrSet(ElemAttributeSet attrSet)2679 public boolean isRecursiveAttrSet(ElemAttributeSet attrSet) 2680 { 2681 2682 if (null == m_attrSetStack) 2683 { 2684 m_attrSetStack = new Stack(); 2685 } 2686 2687 if (!m_attrSetStack.empty()) 2688 { 2689 int loc = m_attrSetStack.search(attrSet); 2690 2691 if (loc > -1) 2692 { 2693 return true; 2694 } 2695 } 2696 2697 return false; 2698 } 2699 2700 /** 2701 * Push an executing attribute set, so we can check for 2702 * recursive attribute definitions. 2703 * 2704 * @param attrSet A non-null ElemAttributeSet reference. 2705 */ pushElemAttributeSet(ElemAttributeSet attrSet)2706 public void pushElemAttributeSet(ElemAttributeSet attrSet) 2707 { 2708 m_attrSetStack.push(attrSet); 2709 } 2710 2711 /** 2712 * Pop the current executing attribute set. 2713 */ popElemAttributeSet()2714 public void popElemAttributeSet() 2715 { 2716 m_attrSetStack.pop(); 2717 } 2718 2719 /** 2720 * Get the table of counters, for optimized xsl:number support. 2721 * 2722 * @return The CountersTable, never null. 2723 */ getCountersTable()2724 public CountersTable getCountersTable() 2725 { 2726 2727 if (null == m_countersTable) 2728 m_countersTable = new CountersTable(); 2729 2730 return m_countersTable; 2731 } 2732 2733 /** 2734 * Tell if the current template rule is null, i.e. if we are 2735 * directly within an apply-templates. Used for xsl:apply-imports. 2736 * 2737 * @return True if the current template rule is null. 2738 */ currentTemplateRuleIsNull()2739 public boolean currentTemplateRuleIsNull() 2740 { 2741 return ((!m_currentTemplateRuleIsNull.isEmpty()) 2742 && (m_currentTemplateRuleIsNull.peek() == true)); 2743 } 2744 2745 /** 2746 * Push true if the current template rule is null, false 2747 * otherwise. 2748 * 2749 * @param b True if the we are executing an xsl:for-each 2750 * (or xsl:call-template?). 2751 */ pushCurrentTemplateRuleIsNull(boolean b)2752 public void pushCurrentTemplateRuleIsNull(boolean b) 2753 { 2754 m_currentTemplateRuleIsNull.push(b); 2755 } 2756 2757 /** 2758 * Push true if the current template rule is null, false 2759 * otherwise. 2760 */ popCurrentTemplateRuleIsNull()2761 public void popCurrentTemplateRuleIsNull() 2762 { 2763 m_currentTemplateRuleIsNull.pop(); 2764 } 2765 2766 /** 2767 * Push a funcion result for the currently active EXSLT 2768 * <code>func:function</code>. 2769 * 2770 * @param val the result of executing an EXSLT 2771 * <code>func:result</code> instruction for the current 2772 * <code>func:function</code>. 2773 */ pushCurrentFuncResult(Object val)2774 public void pushCurrentFuncResult(Object val) { 2775 m_currentFuncResult.push(val); 2776 } 2777 2778 /** 2779 * Pops the result of the currently active EXSLT <code>func:function</code>. 2780 * 2781 * @return the value of the <code>func:function</code> 2782 */ popCurrentFuncResult()2783 public Object popCurrentFuncResult() { 2784 return m_currentFuncResult.pop(); 2785 } 2786 2787 /** 2788 * Determines whether an EXSLT <code>func:result</code> instruction has been 2789 * executed for the currently active EXSLT <code>func:function</code>. 2790 * 2791 * @return <code>true</code> if and only if a <code>func:result</code> 2792 * instruction has been executed 2793 */ currentFuncResultSeen()2794 public boolean currentFuncResultSeen() { 2795 return !m_currentFuncResult.empty() 2796 && m_currentFuncResult.peek() != null; 2797 } 2798 2799 /** 2800 * Return the message manager. 2801 * 2802 * @return The message manager, never null. 2803 */ getMsgMgr()2804 public MsgMgr getMsgMgr() 2805 { 2806 2807 if (null == m_msgMgr) 2808 m_msgMgr = new MsgMgr(this); 2809 2810 return m_msgMgr; 2811 } 2812 2813 /** 2814 * Set the error event listener. 2815 * 2816 * @param listener The new error listener. 2817 * @throws IllegalArgumentException if 2818 */ setErrorListener(ErrorListener listener)2819 public void setErrorListener(ErrorListener listener) 2820 throws IllegalArgumentException 2821 { 2822 2823 synchronized (m_reentryGuard) 2824 { 2825 if (listener == null) 2826 throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_NULL_ERROR_HANDLER, null)); //"Null error handler"); 2827 2828 m_errorHandler = listener; 2829 } 2830 } 2831 2832 /** 2833 * Get the current error event handler. 2834 * 2835 * @return The current error handler, which should never be null. 2836 */ getErrorListener()2837 public ErrorListener getErrorListener() 2838 { 2839 return m_errorHandler; 2840 } 2841 2842 /** 2843 * Look up the value of a feature. 2844 * 2845 * <p>The feature name is any fully-qualified URI. It is 2846 * possible for an TransformerFactory to recognize a feature name but 2847 * to be unable to return its value; this is especially true 2848 * in the case of an adapter for a SAX1 Parser, which has 2849 * no way of knowing whether the underlying parser is 2850 * validating, for example.</p> 2851 * 2852 * <h3>Open issues:</h3> 2853 * <dl> 2854 * <dt><h4>Should getFeature be changed to hasFeature?</h4></dt> 2855 * <dd>Keith Visco writes: Should getFeature be changed to hasFeature? 2856 * It returns a boolean which indicated whether the "state" 2857 * of feature is "true or false". I assume this means whether 2858 * or not a feature is supported? I know SAX is using "getFeature", 2859 * but to me "hasFeature" is cleaner.</dd> 2860 * </dl> 2861 * 2862 * @param name The feature name, which is a fully-qualified 2863 * URI. 2864 * @return The current state of the feature (true or false). 2865 * @throws org.xml.sax.SAXNotRecognizedException When the 2866 * TransformerFactory does not recognize the feature name. 2867 * @throws org.xml.sax.SAXNotSupportedException When the 2868 * TransformerFactory recognizes the feature name but 2869 * cannot determine its value at this time. 2870 * 2871 * @throws SAXNotRecognizedException 2872 * @throws SAXNotSupportedException 2873 */ getFeature(String name)2874 public boolean getFeature(String name) 2875 throws SAXNotRecognizedException, SAXNotSupportedException 2876 { 2877 2878 if ("http://xml.org/trax/features/sax/input".equals(name)) 2879 return true; 2880 else if ("http://xml.org/trax/features/dom/input".equals(name)) 2881 return true; 2882 2883 throw new SAXNotRecognizedException(name); 2884 } 2885 2886 // %TODO% Doc 2887 2888 /** 2889 * NEEDSDOC Method getMode 2890 * 2891 * 2892 * NEEDSDOC (getMode) @return 2893 */ getMode()2894 public QName getMode() 2895 { 2896 return m_modes.isEmpty() ? null : (QName) m_modes.peek(); 2897 } 2898 2899 // %TODO% Doc 2900 2901 /** 2902 * NEEDSDOC Method pushMode 2903 * 2904 * 2905 * NEEDSDOC @param mode 2906 */ pushMode(QName mode)2907 public void pushMode(QName mode) 2908 { 2909 m_modes.push(mode); 2910 } 2911 2912 // %TODO% Doc 2913 2914 /** 2915 * NEEDSDOC Method popMode 2916 * 2917 */ popMode()2918 public void popMode() 2919 { 2920 m_modes.pop(); 2921 } 2922 2923 /** 2924 * Called by SourceTreeHandler to start the transformation 2925 * in a separate thread 2926 * 2927 * NEEDSDOC @param priority 2928 */ runTransformThread(int priority)2929 public void runTransformThread(int priority) 2930 { 2931 2932 // used in SourceTreeHandler 2933 Thread t = ThreadControllerWrapper.runThread(this, priority); 2934 this.setTransformThread(t); 2935 } 2936 2937 /** 2938 * Called by this.transform() if isParserEventsOnMain()==false. 2939 * Similar with runTransformThread(), but no priority is set 2940 * and setTransformThread is not set. 2941 */ runTransformThread()2942 public void runTransformThread() 2943 { 2944 ThreadControllerWrapper.runThread(this, -1); 2945 } 2946 2947 /** 2948 * Called by CoRoutineSAXParser. Launches the CoroutineSAXParser 2949 * in a thread, and prepares it to invoke the parser from that thread 2950 * upon request. 2951 * 2952 */ runTransformThread(Runnable runnable)2953 public static void runTransformThread(Runnable runnable) 2954 { 2955 ThreadControllerWrapper.runThread(runnable, -1); 2956 } 2957 2958 /** 2959 * Used by SourceTreeHandler to wait until the transform 2960 * completes 2961 * 2962 * @throws SAXException 2963 */ waitTransformThread()2964 public void waitTransformThread() throws SAXException 2965 { 2966 2967 // This is called to make sure the task is done. 2968 // It is possible that the thread has been reused - 2969 // but for a different transformation. ( what if we 2970 // recycle the transformer ? Not a problem since this is 2971 // still in use. ) 2972 Thread transformThread = this.getTransformThread(); 2973 2974 if (null != transformThread) 2975 { 2976 try 2977 { 2978 ThreadControllerWrapper.waitThread(transformThread, this); 2979 2980 if (!this.hasTransformThreadErrorCatcher()) 2981 { 2982 Exception e = this.getExceptionThrown(); 2983 2984 if (null != e) 2985 { 2986 e.printStackTrace(); 2987 throw new org.xml.sax.SAXException(e); 2988 } 2989 } 2990 2991 this.setTransformThread(null); 2992 } 2993 catch (InterruptedException ie){} 2994 } 2995 } 2996 2997 /** 2998 * Get the exception thrown by the secondary thread (normally 2999 * the transform thread). 3000 * 3001 * @return The thrown exception, or null if no exception was 3002 * thrown. 3003 */ getExceptionThrown()3004 public Exception getExceptionThrown() 3005 { 3006 return m_exceptionThrown; 3007 } 3008 3009 /** 3010 * Set the exception thrown by the secondary thread (normally 3011 * the transform thread). 3012 * 3013 * @param e The thrown exception, or null if no exception was 3014 * thrown. 3015 */ setExceptionThrown(Exception e)3016 public void setExceptionThrown(Exception e) 3017 { 3018 m_exceptionThrown = e; 3019 } 3020 3021 /** 3022 * This is just a way to set the document for run(). 3023 * 3024 * @param doc A non-null reference to the root of the 3025 * tree to be transformed. 3026 */ setSourceTreeDocForThread(int doc)3027 public void setSourceTreeDocForThread(int doc) 3028 { 3029 m_doc = doc; 3030 } 3031 3032 /** 3033 * From a secondary thread, post the exception, so that 3034 * it can be picked up from the main thread. 3035 * 3036 * @param e The exception that was thrown. 3037 */ postExceptionFromThread(Exception e)3038 void postExceptionFromThread(Exception e) 3039 { 3040 3041 // Commented out in response to problem reported by Nicola Brown <Nicola.Brown@jacobsrimell.com> 3042 // if(m_reportInPostExceptionFromThread) 3043 // { 3044 // // Consider re-throwing the exception if this flag is set. 3045 // e.printStackTrace(); 3046 // } 3047 // %REVIEW Need DTM equivelent? 3048 // if (m_inputContentHandler instanceof SourceTreeHandler) 3049 // { 3050 // SourceTreeHandler sth = (SourceTreeHandler) m_inputContentHandler; 3051 // 3052 // sth.setExceptionThrown(e); 3053 // } 3054 // ContentHandler ch = getContentHandler(); 3055 3056 // if(ch instanceof SourceTreeHandler) 3057 // { 3058 // SourceTreeHandler sth = (SourceTreeHandler) ch; 3059 // ((TransformerImpl)(sth.getTransformer())).postExceptionFromThread(e); 3060 // } 3061 // m_isTransformDone = true; // android-removed 3062 m_exceptionThrown = e; 3063 ; // should have already been reported via the error handler? 3064 3065 synchronized (this) 3066 { 3067 3068 // See message from me on 3/27/2001 to Patrick Moore. 3069 // String msg = e.getMessage(); 3070 // System.out.println(e.getMessage()); 3071 // Is this really needed? -sb 3072 notifyAll(); 3073 3074 // if (null == msg) 3075 // { 3076 // 3077 // // m_throwNewError = false; 3078 // e.printStackTrace(); 3079 // } 3080 // throw new org.apache.xml.utils.WrappedRuntimeException(e); 3081 } 3082 } 3083 3084 /** 3085 * Run the transform thread. 3086 */ run()3087 public void run() 3088 { 3089 3090 m_hasBeenReset = false; 3091 3092 try 3093 { 3094 3095 // int n = ((SourceTreeHandler)getInputContentHandler()).getDTMRoot(); 3096 // transformNode(n); 3097 try 3098 { 3099 // m_isTransformDone = false; // android-removed 3100 3101 // Should no longer be needed... 3102 // if(m_inputContentHandler instanceof TransformerHandlerImpl) 3103 // { 3104 // TransformerHandlerImpl thi = (TransformerHandlerImpl)m_inputContentHandler; 3105 // thi.waitForInitialEvents(); 3106 // } 3107 3108 transformNode(m_doc); 3109 3110 } 3111 catch (Exception e) 3112 { 3113 // e.printStackTrace(); 3114 3115 // Strange that the other catch won't catch this... 3116 if (null != m_transformThread) 3117 postExceptionFromThread(e); // Assume we're on the main thread 3118 else 3119 throw new RuntimeException(e.getMessage()); 3120 } 3121 finally 3122 { 3123 // m_isTransformDone = true; // android-removed 3124 3125 if (m_inputContentHandler instanceof TransformerHandlerImpl) 3126 { 3127 ((TransformerHandlerImpl) m_inputContentHandler).clearCoRoutine(); 3128 } 3129 3130 // synchronized (this) 3131 // { 3132 // notifyAll(); 3133 // } 3134 } 3135 } 3136 catch (Exception e) 3137 { 3138 3139 // e.printStackTrace(); 3140 if (null != m_transformThread) 3141 postExceptionFromThread(e); 3142 else 3143 throw new RuntimeException(e.getMessage()); // Assume we're on the main thread. 3144 } 3145 } 3146 3147 // Fragment re-execution interfaces for a tool. 3148 3149 /** 3150 * Test whether whitespace-only text nodes are visible in the logical 3151 * view of <code>DTM</code>. Normally, this function 3152 * will be called by the implementation of <code>DTM</code>; 3153 * it is not normally called directly from 3154 * user code. 3155 * 3156 * @param elementHandle int Handle of the element. 3157 * @return one of NOTSTRIP, STRIP, or INHERIT. 3158 */ getShouldStripSpace(int elementHandle, DTM dtm)3159 public short getShouldStripSpace(int elementHandle, DTM dtm) 3160 { 3161 3162 try 3163 { 3164 org.apache.xalan.templates.WhiteSpaceInfo info = 3165 m_stylesheetRoot.getWhiteSpaceInfo(m_xcontext, elementHandle, dtm); 3166 3167 if (null == info) 3168 { 3169 return DTMWSFilter.INHERIT; 3170 } 3171 else 3172 { 3173 3174 // System.out.println("getShouldStripSpace: "+info.getShouldStripSpace()); 3175 return info.getShouldStripSpace() 3176 ? DTMWSFilter.STRIP : DTMWSFilter.NOTSTRIP; 3177 } 3178 } 3179 catch (TransformerException se) 3180 { 3181 return DTMWSFilter.INHERIT; 3182 } 3183 } 3184 /** 3185 * Initializer method. 3186 * 3187 * @param transformer non-null transformer instance 3188 * @param realHandler Content Handler instance 3189 */ init(ToXMLSAXHandler h,Transformer transformer, ContentHandler realHandler)3190 public void init(ToXMLSAXHandler h,Transformer transformer, ContentHandler realHandler) 3191 { 3192 h.setTransformer(transformer); 3193 h.setContentHandler(realHandler); 3194 } 3195 setSerializationHandler(SerializationHandler xoh)3196 public void setSerializationHandler(SerializationHandler xoh) 3197 { 3198 m_serializationHandler = xoh; 3199 } 3200 3201 3202 3203 /** 3204 * Fire off characters, cdate events. 3205 * @see org.apache.xml.serializer.SerializerTrace#fireGenerateEvent(int, char[], int, int) 3206 */ fireGenerateEvent( int eventType, char[] ch, int start, int length)3207 public void fireGenerateEvent( 3208 int eventType, 3209 char[] ch, 3210 int start, 3211 int length) { 3212 } 3213 3214 /** 3215 * Fire off startElement, endElement events. 3216 * @see org.apache.xml.serializer.SerializerTrace#fireGenerateEvent(int, String, Attributes) 3217 */ fireGenerateEvent( int eventType, String name, Attributes atts)3218 public void fireGenerateEvent( 3219 int eventType, 3220 String name, 3221 Attributes atts) { 3222 } 3223 3224 /** 3225 * Fire off processingInstruction events. 3226 */ fireGenerateEvent(int eventType, String name, String data)3227 public void fireGenerateEvent(int eventType, String name, String data) { 3228 } 3229 3230 /** 3231 * Fire off comment and entity ref events. 3232 * @see org.apache.xml.serializer.SerializerTrace#fireGenerateEvent(int, String) 3233 */ fireGenerateEvent(int eventType, String data)3234 public void fireGenerateEvent(int eventType, String data) { 3235 } 3236 3237 /** 3238 * Fire off startDocument, endDocument events. 3239 * @see org.apache.xml.serializer.SerializerTrace#fireGenerateEvent(int) 3240 */ fireGenerateEvent(int eventType)3241 public void fireGenerateEvent(int eventType) { 3242 } 3243 3244 /** 3245 * @see org.apache.xml.serializer.SerializerTrace#hasTraceListeners() 3246 */ hasTraceListeners()3247 public boolean hasTraceListeners() { 3248 return false; 3249 } 3250 3251 /** 3252 * @return Incremental flag 3253 */ getIncremental()3254 public boolean getIncremental() { 3255 return m_incremental; 3256 } 3257 3258 /** 3259 * @return Optimization flag 3260 */ getOptimize()3261 public boolean getOptimize() { 3262 return m_optimizer; 3263 } 3264 3265 /** 3266 * @return Source location flag 3267 */ getSource_location()3268 public boolean getSource_location() { 3269 return m_source_location; 3270 } 3271 3272 } // end TransformerImpl class 3273 3274