001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 /* 019 * $Id: StylesheetHandler.java 1225754 2011-12-30 05:31:15Z mrglavas $ 020 */ 021 package org.apache.xalan.processor; 022 023 import java.util.Stack; 024 025 import javax.xml.transform.ErrorListener; 026 import javax.xml.transform.Source; 027 import javax.xml.transform.SourceLocator; 028 import javax.xml.transform.Templates; 029 import javax.xml.transform.TransformerConfigurationException; 030 import javax.xml.transform.TransformerException; 031 import javax.xml.transform.sax.TemplatesHandler; 032 033 import org.apache.xalan.extensions.ExpressionVisitor; 034 import org.apache.xalan.res.XSLMessages; 035 import org.apache.xalan.res.XSLTErrorResources; 036 import org.apache.xalan.templates.Constants; 037 import org.apache.xalan.templates.ElemForEach; 038 import org.apache.xalan.templates.ElemTemplateElement; 039 import org.apache.xalan.templates.Stylesheet; 040 import org.apache.xalan.templates.StylesheetRoot; 041 import org.apache.xml.utils.BoolStack; 042 import org.apache.xml.utils.NamespaceSupport2; 043 import org.apache.xml.utils.NodeConsumer; 044 import org.apache.xml.utils.PrefixResolver; 045 import org.apache.xml.utils.SAXSourceLocator; 046 import org.apache.xml.utils.XMLCharacterRecognizer; 047 import org.apache.xpath.XPath; 048 import org.apache.xpath.compiler.FunctionTable; 049 import org.w3c.dom.Node; 050 import org.xml.sax.Attributes; 051 import org.xml.sax.InputSource; 052 import org.xml.sax.Locator; 053 import org.xml.sax.helpers.DefaultHandler; 054 import org.xml.sax.helpers.NamespaceSupport; 055 056 /** 057 * Initializes and processes a stylesheet via SAX events. 058 * This class acts as essentially a state machine, maintaining 059 * a ContentHandler stack, and pushing appropriate content 060 * handlers as parse events occur. 061 * @xsl.usage advanced 062 */ 063 public class StylesheetHandler extends DefaultHandler 064 implements TemplatesHandler, PrefixResolver, NodeConsumer 065 { 066 067 068 /** 069 * The function table of XPath and XSLT; 070 */ 071 private FunctionTable m_funcTable = new FunctionTable(); 072 073 /** 074 * The flag for the setting of the optimize feature; 075 */ 076 private boolean m_optimize = true; 077 078 /** 079 * The flag for the setting of the incremental feature; 080 */ 081 private boolean m_incremental = false; 082 083 /** 084 * The flag for the setting of the source_location feature; 085 */ 086 private boolean m_source_location = false; 087 088 /** 089 * Create a StylesheetHandler object, creating a root stylesheet 090 * as the target. 091 * 092 * @param processor non-null reference to the transformer factory that owns this handler. 093 * 094 * @throws TransformerConfigurationException if a StylesheetRoot 095 * can not be constructed for some reason. 096 */ 097 public StylesheetHandler(TransformerFactoryImpl processor) 098 throws TransformerConfigurationException 099 { 100 Class func = org.apache.xalan.templates.FuncDocument.class; 101 m_funcTable.installFunction("document", func); 102 103 // func = new org.apache.xalan.templates.FuncKey(); 104 // FunctionTable.installFunction("key", func); 105 func = org.apache.xalan.templates.FuncFormatNumb.class; 106 107 m_funcTable.installFunction("format-number", func); 108 109 m_optimize =((Boolean) processor.getAttribute( 110 TransformerFactoryImpl.FEATURE_OPTIMIZE)).booleanValue(); 111 m_incremental = ((Boolean) processor.getAttribute( 112 TransformerFactoryImpl.FEATURE_INCREMENTAL)).booleanValue(); 113 m_source_location = ((Boolean) processor.getAttribute( 114 TransformerFactoryImpl.FEATURE_SOURCE_LOCATION)).booleanValue(); 115 // m_schema = new XSLTSchema(); 116 init(processor); 117 118 } 119 120 /** 121 * Do common initialization. 122 * 123 * @param processor non-null reference to the transformer factory that owns this handler. 124 */ 125 void init(TransformerFactoryImpl processor) 126 { 127 m_stylesheetProcessor = processor; 128 129 // Set the initial content handler. 130 m_processors.push(m_schema.getElementProcessor()); 131 this.pushNewNamespaceSupport(); 132 133 // m_includeStack.push(SystemIDResolver.getAbsoluteURI(this.getBaseIdentifier(), null)); 134 // initXPath(processor, null); 135 } 136 137 /** 138 * Process an expression string into an XPath. 139 * Must be public for access by the AVT class. 140 * 141 * @param str A non-null reference to a valid or invalid XPath expression string. 142 * 143 * @return A non-null reference to an XPath object that represents the string argument. 144 * 145 * @throws javax.xml.transform.TransformerException if the expression can not be processed. 146 * @see <a href="http://www.w3.org/TR/xslt#section-Expressions">Section 4 Expressions in XSLT Specification</a> 147 */ 148 public XPath createXPath(String str, ElemTemplateElement owningTemplate) 149 throws javax.xml.transform.TransformerException 150 { 151 ErrorListener handler = m_stylesheetProcessor.getErrorListener(); 152 XPath xpath = new XPath(str, owningTemplate, this, XPath.SELECT, handler, 153 m_funcTable); 154 // Visit the expression, registering namespaces for any extension functions it includes. 155 xpath.callVisitors(xpath, new ExpressionVisitor(getStylesheetRoot())); 156 return xpath; 157 } 158 159 /** 160 * Process an expression string into an XPath. 161 * 162 * @param str A non-null reference to a valid or invalid match pattern string. 163 * 164 * @return A non-null reference to an XPath object that represents the string argument. 165 * 166 * @throws javax.xml.transform.TransformerException if the pattern can not be processed. 167 * @see <a href="http://www.w3.org/TR/xslt#patterns">Section 5.2 Patterns in XSLT Specification</a> 168 */ 169 XPath createMatchPatternXPath(String str, ElemTemplateElement owningTemplate) 170 throws javax.xml.transform.TransformerException 171 { 172 ErrorListener handler = m_stylesheetProcessor.getErrorListener(); 173 XPath xpath = new XPath(str, owningTemplate, this, XPath.MATCH, handler, 174 m_funcTable); 175 // Visit the expression, registering namespaces for any extension functions it includes. 176 xpath.callVisitors(xpath, new ExpressionVisitor(getStylesheetRoot())); 177 return xpath; 178 } 179 180 /** 181 * Given a namespace, get the corrisponding prefix from the current 182 * namespace support context. 183 * 184 * @param prefix The prefix to look up, which may be an empty string ("") for the default Namespace. 185 * 186 * @return The associated Namespace URI, or null if the prefix 187 * is undeclared in this context. 188 */ 189 public String getNamespaceForPrefix(String prefix) 190 { 191 return this.getNamespaceSupport().getURI(prefix); 192 } 193 194 /** 195 * Given a namespace, get the corrisponding prefix. This is here only 196 * to support the {@link org.apache.xml.utils.PrefixResolver} interface, 197 * and will throw an error if invoked on this object. 198 * 199 * @param prefix The prefix to look up, which may be an empty string ("") for the default Namespace. 200 * @param context The node context from which to look up the URI. 201 * 202 * @return The associated Namespace URI, or null if the prefix 203 * is undeclared in this context. 204 */ 205 public String getNamespaceForPrefix(String prefix, org.w3c.dom.Node context) 206 { 207 208 // Don't need to support this here. Return the current URI for the prefix, 209 // ignoring the context. 210 assertion(true, "can't process a context node in StylesheetHandler!"); 211 212 return null; 213 } 214 215 /** 216 * Utility function to see if the stack contains the given URL. 217 * 218 * @param stack non-null reference to a Stack. 219 * @param url URL string on which an equality test will be performed. 220 * 221 * @return true if the stack contains the url argument. 222 */ 223 private boolean stackContains(Stack stack, String url) 224 { 225 226 int n = stack.size(); 227 boolean contains = false; 228 229 for (int i = 0; i < n; i++) 230 { 231 String url2 = (String) stack.elementAt(i); 232 233 if (url2.equals(url)) 234 { 235 contains = true; 236 237 break; 238 } 239 } 240 241 return contains; 242 } 243 244 //////////////////////////////////////////////////////////////////// 245 // Implementation of the TRAX TemplatesBuilder interface. 246 //////////////////////////////////////////////////////////////////// 247 248 /** 249 * When this object is used as a ContentHandler or ContentHandler, it will 250 * create a Templates object, which the caller can get once 251 * the SAX events have been completed. 252 * @return The stylesheet object that was created during 253 * the SAX event process, or null if no stylesheet has 254 * been created. 255 * 256 * Author <a href="mailto:scott_boag@lotus.com">Scott Boag</a> 257 * 258 * 259 */ 260 public Templates getTemplates() 261 { 262 return getStylesheetRoot(); 263 } 264 265 /** 266 * Set the base ID (URL or system ID) for the stylesheet 267 * created by this builder. This must be set in order to 268 * resolve relative URLs in the stylesheet. 269 * 270 * @param baseID Base URL for this stylesheet. 271 */ 272 public void setSystemId(String baseID) 273 { 274 pushBaseIndentifier(baseID); 275 } 276 277 /** 278 * Get the base ID (URI or system ID) from where relative 279 * URLs will be resolved. 280 * 281 * @return The systemID that was set with {@link #setSystemId}. 282 */ 283 public String getSystemId() 284 { 285 return this.getBaseIdentifier(); 286 } 287 288 //////////////////////////////////////////////////////////////////// 289 // Implementation of the EntityResolver interface. 290 //////////////////////////////////////////////////////////////////// 291 292 /** 293 * Resolve an external entity. 294 * 295 * @param publicId The public identifer, or null if none is 296 * available. 297 * @param systemId The system identifier provided in the XML 298 * document. 299 * @return The new input source, or null to require the 300 * default behaviour. 301 * 302 * @throws org.xml.sax.SAXException if the entity can not be resolved. 303 */ 304 public InputSource resolveEntity(String publicId, String systemId) 305 throws org.xml.sax.SAXException 306 { 307 return getCurrentProcessor().resolveEntity(this, publicId, systemId); 308 } 309 310 //////////////////////////////////////////////////////////////////// 311 // Implementation of DTDHandler interface. 312 //////////////////////////////////////////////////////////////////// 313 314 /** 315 * Receive notification of a notation declaration. 316 * 317 * <p>By default, do nothing. Application writers may override this 318 * method in a subclass if they wish to keep track of the notations 319 * declared in a document.</p> 320 * 321 * @param name The notation name. 322 * @param publicId The notation public identifier, or null if not 323 * available. 324 * @param systemId The notation system identifier. 325 * @see org.xml.sax.DTDHandler#notationDecl 326 */ 327 public void notationDecl(String name, String publicId, String systemId) 328 { 329 getCurrentProcessor().notationDecl(this, name, publicId, systemId); 330 } 331 332 /** 333 * Receive notification of an unparsed entity declaration. 334 * 335 * @param name The entity name. 336 * @param publicId The entity public identifier, or null if not 337 * available. 338 * @param systemId The entity system identifier. 339 * @param notationName The name of the associated notation. 340 * @see org.xml.sax.DTDHandler#unparsedEntityDecl 341 */ 342 public void unparsedEntityDecl(String name, String publicId, 343 String systemId, String notationName) 344 { 345 getCurrentProcessor().unparsedEntityDecl(this, name, publicId, systemId, 346 notationName); 347 } 348 349 /** 350 * Given a namespace URI, and a local name or a node type, get the processor 351 * for the element, or return null if not allowed. 352 * 353 * @param uri The Namespace URI, or an empty string. 354 * @param localName The local name (without prefix), or empty string if not namespace processing. 355 * @param rawName The qualified name (with prefix). 356 * 357 * @return A non-null reference to a element processor. 358 * 359 * @throws org.xml.sax.SAXException if the element is not allowed in the 360 * found position in the stylesheet. 361 */ 362 XSLTElementProcessor getProcessorFor( 363 String uri, String localName, String rawName) 364 throws org.xml.sax.SAXException 365 { 366 367 XSLTElementProcessor currentProcessor = getCurrentProcessor(); 368 XSLTElementDef def = currentProcessor.getElemDef(); 369 XSLTElementProcessor elemProcessor = def.getProcessorFor(uri, localName); 370 371 if (null == elemProcessor 372 && !(currentProcessor instanceof ProcessorStylesheetDoc) 373 && ((null == getStylesheet() 374 || Double.valueOf(getStylesheet().getVersion()).doubleValue() 375 > Constants.XSLTVERSUPPORTED) 376 ||(!uri.equals(Constants.S_XSLNAMESPACEURL) && 377 currentProcessor instanceof ProcessorStylesheetElement) 378 || getElemVersion() > Constants.XSLTVERSUPPORTED 379 )) 380 { 381 elemProcessor = def.getProcessorForUnknown(uri, localName); 382 } 383 384 if (null == elemProcessor) 385 error(XSLMessages.createMessage(XSLTErrorResources.ER_NOT_ALLOWED_IN_POSITION, new Object[]{rawName}),null);//rawName + " is not allowed in this position in the stylesheet!", 386 387 388 return elemProcessor; 389 } 390 391 //////////////////////////////////////////////////////////////////// 392 // Implementation of ContentHandler interface. 393 //////////////////////////////////////////////////////////////////// 394 395 /** 396 * Receive a Locator object for document events. 397 * This is called by the parser to push a locator for the 398 * stylesheet being parsed. The stack needs to be popped 399 * after the stylesheet has been parsed. We pop in 400 * popStylesheet. 401 * 402 * @param locator A locator for all SAX document events. 403 * @see org.xml.sax.ContentHandler#setDocumentLocator 404 * @see org.xml.sax.Locator 405 */ 406 public void setDocumentLocator(Locator locator) 407 { 408 409 // System.out.println("pushing locator for: "+locator.getSystemId()); 410 m_stylesheetLocatorStack.push(new SAXSourceLocator(locator)); 411 } 412 413 /** 414 * The level of the stylesheet we are at. 415 */ 416 private int m_stylesheetLevel = -1; 417 418 /** 419 * Receive notification of the beginning of the document. 420 * 421 * @see org.xml.sax.ContentHandler#startDocument 422 * 423 * @throws org.xml.sax.SAXException Any SAX exception, possibly 424 * wrapping another exception. 425 */ 426 public void startDocument() throws org.xml.sax.SAXException 427 { 428 m_stylesheetLevel++; 429 pushSpaceHandling(false); 430 } 431 432 /** m_parsingComplete becomes true when the top-level stylesheet and all 433 * its included/imported stylesheets have been been fully parsed, as an 434 * indication that composition/optimization/compilation can begin. 435 * @see isStylesheetParsingComplete */ 436 private boolean m_parsingComplete = false; 437 438 /** 439 * Test whether the _last_ endDocument() has been processed. 440 * This is needed as guidance for stylesheet optimization 441 * and compilation engines, which generally don't want to start 442 * until all included and imported stylesheets have been fully 443 * parsed. 444 * 445 * @return true iff the complete stylesheet tree has been built. 446 */ 447 public boolean isStylesheetParsingComplete() 448 { 449 return m_parsingComplete; 450 } 451 452 /** 453 * Receive notification of the end of the document. 454 * 455 * @see org.xml.sax.ContentHandler#endDocument 456 * 457 * @throws org.xml.sax.SAXException Any SAX exception, possibly 458 * wrapping another exception. 459 */ 460 public void endDocument() throws org.xml.sax.SAXException 461 { 462 463 try 464 { 465 if (null != getStylesheetRoot()) 466 { 467 if (0 == m_stylesheetLevel) 468 getStylesheetRoot().recompose(); 469 } 470 else 471 throw new TransformerException(XSLMessages.createMessage(XSLTErrorResources.ER_NO_STYLESHEETROOT, null)); //"Did not find the stylesheet root!"); 472 473 XSLTElementProcessor elemProcessor = getCurrentProcessor(); 474 475 if (null != elemProcessor) 476 elemProcessor.startNonText(this); 477 478 m_stylesheetLevel--; 479 480 popSpaceHandling(); 481 482 // WARNING: This test works only as long as stylesheets are parsed 483 // more or less recursively. If we switch to an iterative "work-list" 484 // model, this will become true prematurely. In that case, 485 // isStylesheetParsingComplete() will have to be adjusted to be aware 486 // of the worklist. 487 m_parsingComplete = (m_stylesheetLevel < 0); 488 } 489 catch (TransformerException te) 490 { 491 throw new org.xml.sax.SAXException(te); 492 } 493 } 494 495 private java.util.Vector m_prefixMappings = new java.util.Vector(); 496 497 /** 498 * Receive notification of the start of a Namespace mapping. 499 * 500 * <p>By default, do nothing. Application writers may override this 501 * method in a subclass to take specific actions at the start of 502 * each element (such as allocating a new tree node or writing 503 * output to a file).</p> 504 * 505 * @param prefix The Namespace prefix being declared. 506 * @param uri The Namespace URI mapped to the prefix. 507 * @see org.xml.sax.ContentHandler#startPrefixMapping 508 * 509 * @throws org.xml.sax.SAXException Any SAX exception, possibly 510 * wrapping another exception. 511 */ 512 public void startPrefixMapping(String prefix, String uri) 513 throws org.xml.sax.SAXException 514 { 515 516 // m_nsSupport.pushContext(); 517 // this.getNamespaceSupport().declarePrefix(prefix, uri); 518 //m_prefixMappings.add(prefix); // JDK 1.2+ only -sc 519 //m_prefixMappings.add(uri); // JDK 1.2+ only -sc 520 m_prefixMappings.addElement(prefix); // JDK 1.1.x compat -sc 521 m_prefixMappings.addElement(uri); // JDK 1.1.x compat -sc 522 } 523 524 /** 525 * Receive notification of the end of a Namespace mapping. 526 * 527 * <p>By default, do nothing. Application writers may override this 528 * method in a subclass to take specific actions at the start of 529 * each element (such as allocating a new tree node or writing 530 * output to a file).</p> 531 * 532 * @param prefix The Namespace prefix being declared. 533 * @see org.xml.sax.ContentHandler#endPrefixMapping 534 * 535 * @throws org.xml.sax.SAXException Any SAX exception, possibly 536 * wrapping another exception. 537 */ 538 public void endPrefixMapping(String prefix) throws org.xml.sax.SAXException 539 { 540 541 // m_nsSupport.popContext(); 542 } 543 544 /** 545 * Flush the characters buffer. 546 * 547 * @throws org.xml.sax.SAXException 548 */ 549 private void flushCharacters() throws org.xml.sax.SAXException 550 { 551 552 XSLTElementProcessor elemProcessor = getCurrentProcessor(); 553 554 if (null != elemProcessor) 555 elemProcessor.startNonText(this); 556 } 557 558 /** 559 * Receive notification of the start of an element. 560 * 561 * @param uri The Namespace URI, or an empty string. 562 * @param localName The local name (without prefix), or empty string if not namespace processing. 563 * @param rawName The qualified name (with prefix). 564 * @param attributes The specified or defaulted attributes. 565 * 566 * @throws org.xml.sax.SAXException 567 */ 568 public void startElement( 569 String uri, String localName, String rawName, Attributes attributes) 570 throws org.xml.sax.SAXException 571 { 572 NamespaceSupport nssupport = this.getNamespaceSupport(); 573 nssupport.pushContext(); 574 575 int n = m_prefixMappings.size(); 576 577 for (int i = 0; i < n; i++) 578 { 579 String prefix = (String)m_prefixMappings.elementAt(i++); 580 String nsURI = (String)m_prefixMappings.elementAt(i); 581 nssupport.declarePrefix(prefix, nsURI); 582 } 583 //m_prefixMappings.clear(); // JDK 1.2+ only -sc 584 m_prefixMappings.removeAllElements(); // JDK 1.1.x compat -sc 585 586 m_elementID++; 587 588 // This check is currently done for all elements. We should possibly consider 589 // limiting this check to xsl:stylesheet elements only since that is all it really 590 // applies to. Also, it could be bypassed if m_shouldProcess is already true. 591 // In other words, the next two statements could instead look something like this: 592 // if (!m_shouldProcess) 593 // { 594 // if (localName.equals(Constants.ELEMNAME_STYLESHEET_STRING) && 595 // url.equals(Constants.S_XSLNAMESPACEURL)) 596 // { 597 // checkForFragmentID(attributes); 598 // if (!m_shouldProcess) 599 // return; 600 // } 601 // else 602 // return; 603 // } 604 // I didn't include this code statement at this time because in practice 605 // it is a small performance hit and I was waiting to see if its absence 606 // caused a problem. - GLP 607 608 checkForFragmentID(attributes); 609 610 if (!m_shouldProcess) 611 return; 612 613 flushCharacters(); 614 615 pushSpaceHandling(attributes); 616 617 XSLTElementProcessor elemProcessor = getProcessorFor(uri, localName, 618 rawName); 619 620 if(null != elemProcessor) // defensive, for better multiple error reporting. -sb 621 { 622 this.pushProcessor(elemProcessor); 623 elemProcessor.startElement(this, uri, localName, rawName, attributes); 624 } 625 else 626 { 627 m_shouldProcess = false; 628 popSpaceHandling(); 629 } 630 631 } 632 633 /** 634 * Receive notification of the end of an element. 635 * 636 * @param uri The Namespace URI, or an empty string. 637 * @param localName The local name (without prefix), or empty string if not namespace processing. 638 * @param rawName The qualified name (with prefix). 639 * @see org.xml.sax.ContentHandler#endElement 640 * 641 * @throws org.xml.sax.SAXException Any SAX exception, possibly 642 * wrapping another exception. 643 */ 644 public void endElement(String uri, String localName, String rawName) 645 throws org.xml.sax.SAXException 646 { 647 648 m_elementID--; 649 650 if (!m_shouldProcess) 651 return; 652 653 if ((m_elementID + 1) == m_fragmentID) 654 m_shouldProcess = false; 655 656 flushCharacters(); 657 658 popSpaceHandling(); 659 660 XSLTElementProcessor p = getCurrentProcessor(); 661 662 p.endElement(this, uri, localName, rawName); 663 this.popProcessor(); 664 this.getNamespaceSupport().popContext(); 665 } 666 667 /** 668 * Receive notification of character data inside an element. 669 * 670 * @param ch The characters. 671 * @param start The start position in the character array. 672 * @param length The number of characters to use from the 673 * character array. 674 * @see org.xml.sax.ContentHandler#characters 675 * 676 * @throws org.xml.sax.SAXException Any SAX exception, possibly 677 * wrapping another exception. 678 */ 679 public void characters(char ch[], int start, int length) 680 throws org.xml.sax.SAXException 681 { 682 683 if (!m_shouldProcess) 684 return; 685 686 XSLTElementProcessor elemProcessor = getCurrentProcessor(); 687 XSLTElementDef def = elemProcessor.getElemDef(); 688 689 if (def.getType() != XSLTElementDef.T_PCDATA) 690 elemProcessor = def.getProcessorFor(null, "text()"); 691 692 if (null == elemProcessor) 693 { 694 695 // If it's whitespace, just ignore it, otherwise flag an error. 696 if (!XMLCharacterRecognizer.isWhiteSpace(ch, start, length)) 697 error( 698 XSLMessages.createMessage(XSLTErrorResources.ER_NONWHITESPACE_NOT_ALLOWED_IN_POSITION, null),null);//"Non-whitespace text is not allowed in this position in the stylesheet!", 699 700 } 701 else 702 elemProcessor.characters(this, ch, start, length); 703 } 704 705 /** 706 * Receive notification of ignorable whitespace in element content. 707 * 708 * @param ch The whitespace characters. 709 * @param start The start position in the character array. 710 * @param length The number of characters to use from the 711 * character array. 712 * @see org.xml.sax.ContentHandler#ignorableWhitespace 713 * 714 * @throws org.xml.sax.SAXException Any SAX exception, possibly 715 * wrapping another exception. 716 */ 717 public void ignorableWhitespace(char ch[], int start, int length) 718 throws org.xml.sax.SAXException 719 { 720 721 if (!m_shouldProcess) 722 return; 723 724 getCurrentProcessor().ignorableWhitespace(this, ch, start, length); 725 } 726 727 /** 728 * Receive notification of a processing instruction. 729 * 730 * <p>The Parser will invoke this method once for each processing 731 * instruction found: note that processing instructions may occur 732 * before or after the main document element.</p> 733 * 734 * <p>A SAX parser should never report an XML declaration (XML 1.0, 735 * section 2.8) or a text declaration (XML 1.0, section 4.3.1) 736 * using this method.</p> 737 * 738 * <p>By default, do nothing. Application writers may override this 739 * method in a subclass to take specific actions for each 740 * processing instruction, such as setting status variables or 741 * invoking other methods.</p> 742 * 743 * @param target The processing instruction target. 744 * @param data The processing instruction data, or null if 745 * none is supplied. 746 * @see org.xml.sax.ContentHandler#processingInstruction 747 * 748 * @throws org.xml.sax.SAXException Any SAX exception, possibly 749 * wrapping another exception. 750 */ 751 public void processingInstruction(String target, String data) 752 throws org.xml.sax.SAXException 753 { 754 if (!m_shouldProcess) 755 return; 756 757 // Recreating Scott's kluge: 758 // A xsl:for-each or xsl:apply-templates may have a special 759 // PI that tells us not to cache the document. This PI 760 // should really be namespaced. 761 // String localName = getLocalName(target); 762 // String ns = m_stylesheet.getNamespaceFromStack(target); 763 // 764 // %REVIEW%: We need a better PI architecture 765 766 String prefix="",ns="", localName=target; 767 int colon=target.indexOf(':'); 768 if(colon>=0) 769 { 770 ns=getNamespaceForPrefix(prefix=target.substring(0,colon)); 771 localName=target.substring(colon+1); 772 } 773 774 try 775 { 776 // A xsl:for-each or xsl:apply-templates may have a special 777 // PI that tells us not to cache the document. This PI 778 // should really be namespaced... but since the XML Namespaces 779 // spec never defined namespaces as applying to PI's, and since 780 // the testcase we're trying to support is inconsistant in whether 781 // it binds the prefix, I'm going to make this sloppy for 782 // testing purposes. 783 if( 784 "xalan-doc-cache-off".equals(target) || 785 "xalan:doc-cache-off".equals(target) || 786 ("doc-cache-off".equals(localName) && 787 ns.equals("org.apache.xalan.xslt.extensions.Redirect") ) 788 ) 789 { 790 if(!(m_elems.peek() instanceof ElemForEach)) 791 throw new TransformerException 792 ("xalan:doc-cache-off not allowed here!", 793 getLocator()); 794 ElemForEach elem = (ElemForEach)m_elems.peek(); 795 796 elem.m_doc_cache_off = true; 797 798 //System.out.println("JJK***** Recognized <? {"+ns+"}"+prefix+":"+localName+" "+data+"?>"); 799 } 800 } 801 catch(Exception e) 802 { 803 // JJK: Officially, unknown PIs can just be ignored. 804 // Do we want to issue a warning? 805 } 806 807 808 flushCharacters(); 809 getCurrentProcessor().processingInstruction(this, target, data); 810 } 811 812 /** 813 * Receive notification of a skipped entity. 814 * 815 * <p>By default, do nothing. Application writers may override this 816 * method in a subclass to take specific actions for each 817 * processing instruction, such as setting status variables or 818 * invoking other methods.</p> 819 * 820 * @param name The name of the skipped entity. 821 * @see org.xml.sax.ContentHandler#processingInstruction 822 * 823 * @throws org.xml.sax.SAXException Any SAX exception, possibly 824 * wrapping another exception. 825 */ 826 public void skippedEntity(String name) throws org.xml.sax.SAXException 827 { 828 829 if (!m_shouldProcess) 830 return; 831 832 getCurrentProcessor().skippedEntity(this, name); 833 } 834 835 /** 836 * Warn the user of an problem. 837 * 838 * @param msg An key into the {@link org.apache.xalan.res.XSLTErrorResources} 839 * table, that is one of the WG_ prefixed definitions. 840 * @param args An array of arguments for the given warning. 841 * 842 * @throws org.xml.sax.SAXException that wraps a 843 * {@link javax.xml.transform.TransformerException} if the current 844 * {@link javax.xml.transform.ErrorListener#warning} 845 * method chooses to flag this condition as an error. 846 * @xsl.usage internal 847 */ 848 public void warn(String msg, Object args[]) throws org.xml.sax.SAXException 849 { 850 851 String formattedMsg = XSLMessages.createWarning(msg, args); 852 SAXSourceLocator locator = getLocator(); 853 ErrorListener handler = m_stylesheetProcessor.getErrorListener(); 854 855 try 856 { 857 if (null != handler) 858 handler.warning(new TransformerException(formattedMsg, locator)); 859 } 860 catch (TransformerException te) 861 { 862 throw new org.xml.sax.SAXException(te); 863 } 864 } 865 866 /** 867 * Assert that a condition is true. If it is not true, throw an error. 868 * 869 * @param condition false if an error should not be thrown, otherwise true. 870 * @param msg Error message to be passed to the RuntimeException as an 871 * argument. 872 * @throws RuntimeException if the condition is not true. 873 * @xsl.usage internal 874 */ 875 private void assertion(boolean condition, String msg) throws RuntimeException 876 { 877 if (!condition) 878 throw new RuntimeException(msg); 879 } 880 881 /** 882 * Tell the user of an error, and probably throw an 883 * exception. 884 * 885 * @param msg An error message. 886 * @param e An error which the SAXException should wrap. 887 * 888 * @throws org.xml.sax.SAXException that wraps a 889 * {@link javax.xml.transform.TransformerException} if the current 890 * {@link javax.xml.transform.ErrorListener#error} 891 * method chooses to flag this condition as an error. 892 * @xsl.usage internal 893 */ 894 protected void error(String msg, Exception e) 895 throws org.xml.sax.SAXException 896 { 897 898 SAXSourceLocator locator = getLocator(); 899 ErrorListener handler = m_stylesheetProcessor.getErrorListener(); 900 TransformerException pe; 901 902 if (!(e instanceof TransformerException)) 903 { 904 pe = (null == e) 905 ? new TransformerException(msg, locator) 906 : new TransformerException(msg, locator, e); 907 } 908 else 909 pe = (TransformerException) e; 910 911 if (null != handler) 912 { 913 try 914 { 915 handler.error(pe); 916 } 917 catch (TransformerException te) 918 { 919 throw new org.xml.sax.SAXException(te); 920 } 921 } 922 else 923 throw new org.xml.sax.SAXException(pe); 924 } 925 926 /** 927 * Tell the user of an error, and probably throw an 928 * exception. 929 * 930 * @param msg A key into the {@link org.apache.xalan.res.XSLTErrorResources} 931 * table, that is one of the WG_ prefixed definitions. 932 * @param args An array of arguments for the given warning. 933 * @param e An error which the SAXException should wrap. 934 * 935 * @throws org.xml.sax.SAXException that wraps a 936 * {@link javax.xml.transform.TransformerException} if the current 937 * {@link javax.xml.transform.ErrorListener#error} 938 * method chooses to flag this condition as an error. 939 * @xsl.usage internal 940 */ 941 protected void error(String msg, Object args[], Exception e) 942 throws org.xml.sax.SAXException 943 { 944 945 String formattedMsg = XSLMessages.createMessage(msg, args); 946 947 error(formattedMsg, e); 948 } 949 950 /** 951 * Receive notification of a XSLT processing warning. 952 * 953 * @param e The warning information encoded as an exception. 954 * 955 * @throws org.xml.sax.SAXException that wraps a 956 * {@link javax.xml.transform.TransformerException} if the current 957 * {@link javax.xml.transform.ErrorListener#warning} 958 * method chooses to flag this condition as an error. 959 */ 960 public void warning(org.xml.sax.SAXParseException e) 961 throws org.xml.sax.SAXException 962 { 963 964 String formattedMsg = e.getMessage(); 965 SAXSourceLocator locator = getLocator(); 966 ErrorListener handler = m_stylesheetProcessor.getErrorListener(); 967 968 try 969 { 970 handler.warning(new TransformerException(formattedMsg, locator)); 971 } 972 catch (TransformerException te) 973 { 974 throw new org.xml.sax.SAXException(te); 975 } 976 } 977 978 /** 979 * Receive notification of a recoverable XSLT processing error. 980 * 981 * @param e The error information encoded as an exception. 982 * 983 * @throws org.xml.sax.SAXException that wraps a 984 * {@link javax.xml.transform.TransformerException} if the current 985 * {@link javax.xml.transform.ErrorListener#error} 986 * method chooses to flag this condition as an error. 987 */ 988 public void error(org.xml.sax.SAXParseException e) 989 throws org.xml.sax.SAXException 990 { 991 992 String formattedMsg = e.getMessage(); 993 SAXSourceLocator locator = getLocator(); 994 ErrorListener handler = m_stylesheetProcessor.getErrorListener(); 995 996 try 997 { 998 handler.error(new TransformerException(formattedMsg, locator)); 999 } 1000 catch (TransformerException te) 1001 { 1002 throw new org.xml.sax.SAXException(te); 1003 } 1004 } 1005 1006 /** 1007 * Report a fatal XSLT processing error. 1008 * 1009 * @param e The error information encoded as an exception. 1010 * 1011 * @throws org.xml.sax.SAXException that wraps a 1012 * {@link javax.xml.transform.TransformerException} if the current 1013 * {@link javax.xml.transform.ErrorListener#fatalError} 1014 * method chooses to flag this condition as an error. 1015 */ 1016 public void fatalError(org.xml.sax.SAXParseException e) 1017 throws org.xml.sax.SAXException 1018 { 1019 1020 String formattedMsg = e.getMessage(); 1021 SAXSourceLocator locator = getLocator(); 1022 ErrorListener handler = m_stylesheetProcessor.getErrorListener(); 1023 1024 try 1025 { 1026 handler.fatalError(new TransformerException(formattedMsg, locator)); 1027 } 1028 catch (TransformerException te) 1029 { 1030 throw new org.xml.sax.SAXException(te); 1031 } 1032 } 1033 1034 /** 1035 * If we have a URL to a XML fragment, this is set 1036 * to false until the ID is found. 1037 * (warning: I worry that this should be in a stack). 1038 */ 1039 private boolean m_shouldProcess = true; 1040 1041 /** 1042 * If we have a URL to a XML fragment, the value is stored 1043 * in this string, and the m_shouldProcess flag is set to 1044 * false until we match an ID with this string. 1045 * (warning: I worry that this should be in a stack). 1046 */ 1047 private String m_fragmentIDString; 1048 1049 /** 1050 * Keep track of the elementID, so we can tell when 1051 * is has completed. This isn't a real ID, but rather 1052 * a nesting level. However, it's good enough for 1053 * our purposes. 1054 * (warning: I worry that this should be in a stack). 1055 */ 1056 private int m_elementID = 0; 1057 1058 /** 1059 * The ID of the fragment that has been found 1060 * (warning: I worry that this should be in a stack). 1061 */ 1062 private int m_fragmentID = 0; 1063 1064 /** 1065 * Check to see if an ID attribute matched the #id, called 1066 * from startElement. 1067 * 1068 * @param attributes The specified or defaulted attributes. 1069 */ 1070 private void checkForFragmentID(Attributes attributes) 1071 { 1072 1073 if (!m_shouldProcess) 1074 { 1075 if ((null != attributes) && (null != m_fragmentIDString)) 1076 { 1077 int n = attributes.getLength(); 1078 1079 for (int i = 0; i < n; i++) 1080 { 1081 String name = attributes.getQName(i); 1082 1083 if (name.equals(Constants.ATTRNAME_ID)) 1084 { 1085 String val = attributes.getValue(i); 1086 1087 if (val.equalsIgnoreCase(m_fragmentIDString)) 1088 { 1089 m_shouldProcess = true; 1090 m_fragmentID = m_elementID; 1091 } 1092 } 1093 } 1094 } 1095 } 1096 } 1097 1098 /** 1099 * The XSLT TransformerFactory for needed services. 1100 */ 1101 private TransformerFactoryImpl m_stylesheetProcessor; 1102 1103 /** 1104 * Get the XSLT TransformerFactoryImpl for needed services. 1105 * TODO: This method should be renamed. 1106 * 1107 * @return The TransformerFactoryImpl that owns this handler. 1108 */ 1109 public TransformerFactoryImpl getStylesheetProcessor() 1110 { 1111 return m_stylesheetProcessor; 1112 } 1113 1114 /** 1115 * If getStylesheetType returns this value, the current stylesheet 1116 * is a root stylesheet. 1117 * @xsl.usage internal 1118 */ 1119 public static final int STYPE_ROOT = 1; 1120 1121 /** 1122 * If getStylesheetType returns this value, the current stylesheet 1123 * is an included stylesheet. 1124 * @xsl.usage internal 1125 */ 1126 public static final int STYPE_INCLUDE = 2; 1127 1128 /** 1129 * If getStylesheetType returns this value, the current stylesheet 1130 * is an imported stylesheet. 1131 * @xsl.usage internal 1132 */ 1133 public static final int STYPE_IMPORT = 3; 1134 1135 /** The current stylesheet type. */ 1136 private int m_stylesheetType = STYPE_ROOT; 1137 1138 /** 1139 * Get the type of stylesheet that should be built 1140 * or is being processed. 1141 * 1142 * @return one of STYPE_ROOT, STYPE_INCLUDE, or STYPE_IMPORT. 1143 */ 1144 int getStylesheetType() 1145 { 1146 return m_stylesheetType; 1147 } 1148 1149 /** 1150 * Set the type of stylesheet that should be built 1151 * or is being processed. 1152 * 1153 * @param type Must be one of STYPE_ROOT, STYPE_INCLUDE, or STYPE_IMPORT. 1154 */ 1155 void setStylesheetType(int type) 1156 { 1157 m_stylesheetType = type; 1158 } 1159 1160 /** 1161 * The stack of stylesheets being processed. 1162 */ 1163 private Stack m_stylesheets = new Stack(); 1164 1165 /** 1166 * Return the stylesheet that this handler is constructing. 1167 * 1168 * @return The current stylesheet that is on top of the stylesheets stack, 1169 * or null if no stylesheet is on the stylesheets stack. 1170 */ 1171 Stylesheet getStylesheet() 1172 { 1173 return (m_stylesheets.size() == 0) 1174 ? null : (Stylesheet) m_stylesheets.peek(); 1175 } 1176 1177 /** 1178 * Return the last stylesheet that was popped off the stylesheets stack. 1179 * 1180 * @return The last popped stylesheet, or null. 1181 */ 1182 Stylesheet getLastPoppedStylesheet() 1183 { 1184 return m_lastPoppedStylesheet; 1185 } 1186 1187 /** 1188 * Return the stylesheet root that this handler is constructing. 1189 * 1190 * @return The root stylesheet of the stylesheets tree. 1191 */ 1192 public StylesheetRoot getStylesheetRoot() 1193 { 1194 if (m_stylesheetRoot != null){ 1195 m_stylesheetRoot.setOptimizer(m_optimize); 1196 m_stylesheetRoot.setIncremental(m_incremental); 1197 m_stylesheetRoot.setSource_location(m_source_location); 1198 } 1199 return m_stylesheetRoot; 1200 } 1201 1202 /** The root stylesheet of the stylesheets tree. */ 1203 StylesheetRoot m_stylesheetRoot; 1204 1205 /** The last stylesheet that was popped off the stylesheets stack. */ 1206 Stylesheet m_lastPoppedStylesheet; 1207 1208 /** 1209 * Push the current stylesheet being constructed. If no other stylesheets 1210 * have been pushed onto the stack, assume the argument is a stylesheet 1211 * root, and also set the stylesheet root member. 1212 * 1213 * @param s non-null reference to a stylesheet. 1214 */ 1215 public void pushStylesheet(Stylesheet s) 1216 { 1217 1218 if (m_stylesheets.size() == 0) 1219 m_stylesheetRoot = (StylesheetRoot) s; 1220 1221 m_stylesheets.push(s); 1222 } 1223 1224 /** 1225 * Pop the last stylesheet pushed, and return the stylesheet that this 1226 * handler is constructing, and set the last popped stylesheet member. 1227 * Also pop the stylesheet locator stack. 1228 * 1229 * @return The stylesheet popped off the stack, or the last popped stylesheet. 1230 */ 1231 Stylesheet popStylesheet() 1232 { 1233 1234 // The stylesheetLocatorStack needs to be popped because 1235 // a locator was pushed in for this stylesheet by the SAXparser by calling 1236 // setDocumentLocator(). 1237 if (!m_stylesheetLocatorStack.isEmpty()) 1238 m_stylesheetLocatorStack.pop(); 1239 1240 if (!m_stylesheets.isEmpty()) 1241 m_lastPoppedStylesheet = (Stylesheet) m_stylesheets.pop(); 1242 1243 // Shouldn't this be null if stylesheets is empty? -sb 1244 return m_lastPoppedStylesheet; 1245 } 1246 1247 /** 1248 * The stack of current processors. 1249 */ 1250 private Stack m_processors = new Stack(); 1251 1252 /** 1253 * Get the current XSLTElementProcessor at the top of the stack. 1254 * 1255 * @return Valid XSLTElementProcessor, which should never be null. 1256 */ 1257 XSLTElementProcessor getCurrentProcessor() 1258 { 1259 return (XSLTElementProcessor) m_processors.peek(); 1260 } 1261 1262 /** 1263 * Push the current XSLTElementProcessor onto the top of the stack. 1264 * 1265 * @param processor non-null reference to the current element processor. 1266 */ 1267 void pushProcessor(XSLTElementProcessor processor) 1268 { 1269 m_processors.push(processor); 1270 } 1271 1272 /** 1273 * Pop the current XSLTElementProcessor from the top of the stack. 1274 * @return the XSLTElementProcessor which was popped. 1275 */ 1276 XSLTElementProcessor popProcessor() 1277 { 1278 return (XSLTElementProcessor) m_processors.pop(); 1279 } 1280 1281 /** 1282 * The root of the XSLT Schema, which tells us how to 1283 * transition content handlers, create elements, etc. 1284 * For the moment at least, this can't be static, since 1285 * the processors store state. 1286 */ 1287 private XSLTSchema m_schema = new XSLTSchema(); 1288 1289 /** 1290 * Get the root of the XSLT Schema, which tells us how to 1291 * transition content handlers, create elements, etc. 1292 * 1293 * @return The root XSLT Schema, which should never be null. 1294 * @xsl.usage internal 1295 */ 1296 public XSLTSchema getSchema() 1297 { 1298 return m_schema; 1299 } 1300 1301 /** 1302 * The stack of elements, pushed and popped as events occur. 1303 */ 1304 private Stack m_elems = new Stack(); 1305 1306 /** 1307 * Get the current ElemTemplateElement at the top of the stack. 1308 * @return Valid ElemTemplateElement, which may be null. 1309 */ 1310 ElemTemplateElement getElemTemplateElement() 1311 { 1312 1313 try 1314 { 1315 return (ElemTemplateElement) m_elems.peek(); 1316 } 1317 catch (java.util.EmptyStackException ese) 1318 { 1319 return null; 1320 } 1321 } 1322 1323 /** An increasing number that is used to indicate the order in which this element 1324 * was encountered during the parse of the XSLT tree. 1325 */ 1326 private int m_docOrderCount = 0; 1327 1328 /** 1329 * Returns the next m_docOrderCount number and increments the number for future use. 1330 */ 1331 int nextUid() 1332 { 1333 return m_docOrderCount++; 1334 } 1335 1336 /** 1337 * Push the current XSLTElementProcessor to the top of the stack. As a 1338 * side-effect, set the document order index (simply because this is a 1339 * convenient place to set it). 1340 * 1341 * @param elem Should be a non-null reference to the intended current 1342 * template element. 1343 */ 1344 void pushElemTemplateElement(ElemTemplateElement elem) 1345 { 1346 1347 if (elem.getUid() == -1) 1348 elem.setUid(nextUid()); 1349 1350 m_elems.push(elem); 1351 } 1352 1353 /** 1354 * Get the current XSLTElementProcessor from the top of the stack. 1355 * @return the ElemTemplateElement which was popped. 1356 */ 1357 ElemTemplateElement popElemTemplateElement() 1358 { 1359 return (ElemTemplateElement) m_elems.pop(); 1360 } 1361 1362 /** 1363 * This will act as a stack to keep track of the 1364 * current include base. 1365 */ 1366 Stack m_baseIdentifiers = new Stack(); 1367 1368 /** 1369 * Push a base identifier onto the base URI stack. 1370 * 1371 * @param baseID The current base identifier for this position in the 1372 * stylesheet, which may be a fragment identifier, or which may be null. 1373 * @see <a href="http://www.w3.org/TR/xslt#base-uri"> 1374 * Section 3.2 Base URI of XSLT specification.</a> 1375 */ 1376 void pushBaseIndentifier(String baseID) 1377 { 1378 1379 if (null != baseID) 1380 { 1381 int posOfHash = baseID.indexOf('#'); 1382 1383 if (posOfHash > -1) 1384 { 1385 m_fragmentIDString = baseID.substring(posOfHash + 1); 1386 m_shouldProcess = false; 1387 } 1388 else 1389 m_shouldProcess = true; 1390 } 1391 else 1392 m_shouldProcess = true; 1393 1394 m_baseIdentifiers.push(baseID); 1395 } 1396 1397 /** 1398 * Pop a base URI from the stack. 1399 * @return baseIdentifier. 1400 */ 1401 String popBaseIndentifier() 1402 { 1403 return (String) m_baseIdentifiers.pop(); 1404 } 1405 1406 /** 1407 * Return the base identifier. 1408 * 1409 * @return The base identifier of the current stylesheet. 1410 */ 1411 public String getBaseIdentifier() 1412 { 1413 1414 // Try to get the baseIdentifier from the baseIdentifier's stack, 1415 // which may not be the same thing as the value found in the 1416 // SourceLocators stack. 1417 String base = (String) (m_baseIdentifiers.isEmpty() 1418 ? null : m_baseIdentifiers.peek()); 1419 1420 // Otherwise try the stylesheet. 1421 if (null == base) 1422 { 1423 SourceLocator locator = getLocator(); 1424 1425 base = (null == locator) ? "" : locator.getSystemId(); 1426 } 1427 1428 return base; 1429 } 1430 1431 /** 1432 * The top of this stack should contain the currently processed 1433 * stylesheet SAX locator object. 1434 */ 1435 private Stack m_stylesheetLocatorStack = new Stack(); 1436 1437 /** 1438 * Get the current stylesheet Locator object. 1439 * 1440 * @return non-null reference to the current locator object. 1441 */ 1442 public SAXSourceLocator getLocator() 1443 { 1444 1445 if (m_stylesheetLocatorStack.isEmpty()) 1446 { 1447 SAXSourceLocator locator = new SAXSourceLocator(); 1448 1449 locator.setSystemId(this.getStylesheetProcessor().getDOMsystemID()); 1450 1451 return locator; 1452 1453 // m_stylesheetLocatorStack.push(locator); 1454 } 1455 1456 return ((SAXSourceLocator) m_stylesheetLocatorStack.peek()); 1457 } 1458 1459 /** 1460 * A stack of URL hrefs for imported stylesheets. This is 1461 * used to diagnose circular imports. 1462 */ 1463 private Stack m_importStack = new Stack(); 1464 1465 /** 1466 * A stack of Source objects obtained from a URIResolver, 1467 * for each element in this stack there is a 1-1 correspondence 1468 * with an element in the m_importStack. 1469 */ 1470 private Stack m_importSourceStack = new Stack(); 1471 1472 /** 1473 * Push an import href onto the stylesheet stack. 1474 * 1475 * @param hrefUrl non-null reference to the URL for the current imported 1476 * stylesheet. 1477 */ 1478 void pushImportURL(String hrefUrl) 1479 { 1480 m_importStack.push(hrefUrl); 1481 } 1482 1483 /** 1484 * Push the Source of an import href onto the stylesheet stack, 1485 * obtained from a URIResolver, null if there is no URIResolver, 1486 * or if that resolver returned null. 1487 */ 1488 void pushImportSource(Source sourceFromURIResolver) 1489 { 1490 m_importSourceStack.push(sourceFromURIResolver); 1491 } 1492 1493 /** 1494 * See if the imported stylesheet stack already contains 1495 * the given URL. Used to test for recursive imports. 1496 * 1497 * @param hrefUrl non-null reference to a URL string. 1498 * 1499 * @return true if the URL is on the import stack. 1500 */ 1501 boolean importStackContains(String hrefUrl) 1502 { 1503 return stackContains(m_importStack, hrefUrl); 1504 } 1505 1506 /** 1507 * Pop an import href from the stylesheet stack. 1508 * 1509 * @return non-null reference to the import URL that was popped. 1510 */ 1511 String popImportURL() 1512 { 1513 return (String) m_importStack.pop(); 1514 } 1515 1516 String peekImportURL() 1517 { 1518 return (String) m_importStack.peek(); 1519 } 1520 1521 Source peekSourceFromURIResolver() 1522 { 1523 return (Source) m_importSourceStack.peek(); 1524 } 1525 1526 /** 1527 * Pop a Source from a user provided URIResolver, corresponding 1528 * to the URL popped from the m_importStack. 1529 */ 1530 Source popImportSource() 1531 { 1532 return (Source) m_importSourceStack.pop(); 1533 } 1534 1535 /** 1536 * If this is set to true, we've already warned about using the 1537 * older XSLT namespace URL. 1538 */ 1539 private boolean warnedAboutOldXSLTNamespace = false; 1540 1541 /** Stack of NamespaceSupport objects. */ 1542 Stack m_nsSupportStack = new Stack(); 1543 1544 /** 1545 * Push a new NamespaceSupport instance. 1546 */ 1547 void pushNewNamespaceSupport() 1548 { 1549 m_nsSupportStack.push(new NamespaceSupport2()); 1550 } 1551 1552 /** 1553 * Pop the current NamespaceSupport object. 1554 * 1555 */ 1556 void popNamespaceSupport() 1557 { 1558 m_nsSupportStack.pop(); 1559 } 1560 1561 /** 1562 * Get the current NamespaceSupport object. 1563 * 1564 * @return a non-null reference to the current NamespaceSupport object, 1565 * which is the top of the namespace support stack. 1566 */ 1567 NamespaceSupport getNamespaceSupport() 1568 { 1569 return (NamespaceSupport) m_nsSupportStack.peek(); 1570 } 1571 1572 /** 1573 * The originating node if the current stylesheet is being created 1574 * from a DOM. 1575 * @see org.apache.xml.utils.NodeConsumer 1576 */ 1577 private Node m_originatingNode; 1578 1579 /** 1580 * Set the node that is originating the SAX event. 1581 * 1582 * @param n Reference to node that originated the current event. 1583 * @see org.apache.xml.utils.NodeConsumer 1584 */ 1585 public void setOriginatingNode(Node n) 1586 { 1587 m_originatingNode = n; 1588 } 1589 1590 /** 1591 * Set the node that is originating the SAX event. 1592 * 1593 * @return Reference to node that originated the current event. 1594 * @see org.apache.xml.utils.NodeConsumer 1595 */ 1596 public Node getOriginatingNode() 1597 { 1598 return m_originatingNode; 1599 } 1600 1601 /** 1602 * Stack of booleans that are pushed and popped in start/endElement depending 1603 * on the value of xml:space=default/preserve. 1604 */ 1605 private BoolStack m_spacePreserveStack = new BoolStack(); 1606 1607 /** 1608 * Return boolean value from the spacePreserve stack depending on the value 1609 * of xml:space=default/preserve. 1610 * 1611 * @return true if space should be preserved, false otherwise. 1612 */ 1613 boolean isSpacePreserve() 1614 { 1615 return m_spacePreserveStack.peek(); 1616 } 1617 1618 /** 1619 * Pop boolean value from the spacePreserve stack. 1620 */ 1621 void popSpaceHandling() 1622 { 1623 m_spacePreserveStack.pop(); 1624 } 1625 1626 /** 1627 * Push boolean value on to the spacePreserve stack. 1628 * 1629 * @param b true if space should be preserved, false otherwise. 1630 */ 1631 void pushSpaceHandling(boolean b) 1632 throws org.xml.sax.SAXParseException 1633 { 1634 m_spacePreserveStack.push(b); 1635 } 1636 1637 /** 1638 * Push boolean value on to the spacePreserve stack depending on the value 1639 * of xml:space=default/preserve. 1640 * 1641 * @param attrs list of attributes that were passed to startElement. 1642 */ 1643 void pushSpaceHandling(Attributes attrs) 1644 throws org.xml.sax.SAXParseException 1645 { 1646 String value = attrs.getValue("xml:space"); 1647 if(null == value) 1648 { 1649 m_spacePreserveStack.push(m_spacePreserveStack.peekOrFalse()); 1650 } 1651 else if(value.equals("preserve")) 1652 { 1653 m_spacePreserveStack.push(true); 1654 } 1655 else if(value.equals("default")) 1656 { 1657 m_spacePreserveStack.push(false); 1658 } 1659 else 1660 { 1661 SAXSourceLocator locator = getLocator(); 1662 ErrorListener handler = m_stylesheetProcessor.getErrorListener(); 1663 1664 try 1665 { 1666 handler.error(new TransformerException(XSLMessages.createMessage(XSLTErrorResources.ER_ILLEGAL_XMLSPACE_VALUE, null), locator)); //"Illegal value for xml:space", locator)); 1667 } 1668 catch (TransformerException te) 1669 { 1670 throw new org.xml.sax.SAXParseException(te.getMessage(), locator, te); 1671 } 1672 m_spacePreserveStack.push(m_spacePreserveStack.peek()); 1673 } 1674 } 1675 1676 private double getElemVersion() 1677 { 1678 ElemTemplateElement elem = getElemTemplateElement(); 1679 double version = -1; 1680 while ((version == -1 || version == Constants.XSLTVERSUPPORTED) && elem != null) 1681 { 1682 try{ 1683 version = Double.valueOf(elem.getXmlVersion()).doubleValue(); 1684 } 1685 catch (Exception ex) 1686 { 1687 version = -1; 1688 } 1689 elem = elem.getParentElem(); 1690 } 1691 return (version == -1)? Constants.XSLTVERSUPPORTED : version; 1692 } 1693 /** 1694 * @see PrefixResolver#handlesNullPrefixes() 1695 */ 1696 public boolean handlesNullPrefixes() { 1697 return false; 1698 } 1699 1700 /** 1701 * @return Optimization flag 1702 */ 1703 public boolean getOptimize() { 1704 return m_optimize; 1705 } 1706 1707 /** 1708 * @return Incremental flag 1709 */ 1710 public boolean getIncremental() { 1711 return m_incremental; 1712 } 1713 1714 /** 1715 * @return Source Location flag 1716 */ 1717 public boolean getSource_location() { 1718 return m_source_location; 1719 } 1720 1721 } 1722 1723 1724