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