1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 1999 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Xalan" and "Apache Software Foundation" must
  28. * not be used to endorse or promote products derived from this
  29. * software without prior written permission. For written
  30. * permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * nor may "Apache" appear in their name, without prior written
  34. * permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation and was
  52. * originally based on software copyright (c) 1999, Lotus
  53. * Development Corporation., http://www.lotus.com. For more
  54. * information on the Apache Software Foundation, please see
  55. * <http://www.apache.org/>.
  56. */
  57. package org.apache.xalan.processor;
  58. import java.net.URL;
  59. import java.io.IOException;
  60. import javax.xml.transform.sax.TemplatesHandler;
  61. import javax.xml.transform.Templates;
  62. import javax.xml.transform.TransformerException;
  63. import javax.xml.transform.TransformerConfigurationException;
  64. import java.util.Stack;
  65. import org.apache.xalan.res.XSLMessages;
  66. import org.apache.xalan.res.XSLTErrorResources;
  67. import org.apache.xalan.templates.Constants;
  68. import org.apache.xalan.templates.ElemTemplateElement;
  69. import org.apache.xalan.templates.ElemUnknown;
  70. import org.apache.xalan.templates.ElemForEach;
  71. import org.apache.xalan.templates.StylesheetRoot;
  72. import org.apache.xalan.templates.Stylesheet;
  73. import org.apache.xml.utils.NodeConsumer;
  74. import org.apache.xml.utils.PrefixResolver;
  75. import org.apache.xml.utils.XMLCharacterRecognizer;
  76. import org.apache.xml.utils.BoolStack;
  77. import org.apache.xpath.compiler.FunctionTable;
  78. import org.apache.xpath.compiler.XPathParser;
  79. import org.apache.xpath.functions.Function;
  80. import org.apache.xpath.XPathFactory;
  81. import org.apache.xpath.XPath;
  82. import org.apache.xpath.functions.FuncExtFunction;
  83. import org.apache.xalan.extensions.ExpressionVisitor;
  84. import org.w3c.dom.Node;
  85. import org.xml.sax.Attributes;
  86. import org.xml.sax.ContentHandler;
  87. import org.xml.sax.DTDHandler;
  88. import org.xml.sax.EntityResolver;
  89. import org.xml.sax.InputSource;
  90. import org.xml.sax.Locator;
  91. import org.xml.sax.helpers.NamespaceSupport;
  92. import org.apache.xml.utils.NamespaceSupport2;
  93. import org.xml.sax.helpers.DefaultHandler;
  94. import javax.xml.transform.SourceLocator;
  95. import javax.xml.transform.ErrorListener;
  96. import javax.xml.transform.TransformerException;
  97. import org.apache.xml.utils.SAXSourceLocator;
  98. /**
  99. * <meta name="usage" content="advanced"/>
  100. * Initializes and processes a stylesheet via SAX events.
  101. * This class acts as essentially a state machine, maintaining
  102. * a ContentHandler stack, and pushing appropriate content
  103. * handlers as parse events occur.
  104. */
  105. public class StylesheetHandler extends DefaultHandler
  106. implements TemplatesHandler, PrefixResolver, NodeConsumer
  107. {
  108. /**
  109. * Create a StylesheetHandler object, creating a root stylesheet
  110. * as the target.
  111. *
  112. * @param processor non-null reference to the transformer factory that owns this handler.
  113. *
  114. * @throws TransformerConfigurationException if a StylesheetRoot
  115. * can not be constructed for some reason.
  116. */
  117. public StylesheetHandler(TransformerFactoryImpl processor)
  118. throws TransformerConfigurationException
  119. {
  120. // m_schema = new XSLTSchema();
  121. init(processor);
  122. }
  123. /**
  124. * Static flag to let us know if the XPath functions table
  125. * has been initialized.
  126. */
  127. private static boolean m_xpathFunctionsInited = false;
  128. /**
  129. * Do common initialization.
  130. *
  131. * @param processor non-null reference to the transformer factory that owns this handler.
  132. */
  133. void init(TransformerFactoryImpl processor)
  134. {
  135. // Not sure about double-check of this flag, but
  136. // it seems safe...
  137. if (false == m_xpathFunctionsInited)
  138. {
  139. synchronized (this)
  140. {
  141. if (false == m_xpathFunctionsInited)
  142. {
  143. m_xpathFunctionsInited = true;
  144. Function func = new org.apache.xalan.templates.FuncDocument();
  145. FunctionTable.installFunction("document", func);
  146. // func = new org.apache.xalan.templates.FuncKey();
  147. // FunctionTable.installFunction("key", func);
  148. func = new org.apache.xalan.templates.FuncFormatNumb();
  149. FunctionTable.installFunction("format-number", func);
  150. }
  151. }
  152. }
  153. m_stylesheetProcessor = processor;
  154. // Set the initial content handler.
  155. m_processors.push(m_schema.getElementProcessor());
  156. this.pushNewNamespaceSupport();
  157. // m_includeStack.push(SystemIDResolver.getAbsoluteURI(this.getBaseIdentifier(), null));
  158. // initXPath(processor, null);
  159. }
  160. /**
  161. * Process an expression string into an XPath.
  162. * Must be public for access by the AVT class.
  163. *
  164. * @param str A non-null reference to a valid or invalid XPath expression string.
  165. *
  166. * @return A non-null reference to an XPath object that represents the string argument.
  167. *
  168. * @throws javax.xml.transform.TransformerException if the expression can not be processed.
  169. * @see <a href="http://www.w3.org/TR/xslt#section-Expressions">Section 4 Expressions in XSLT Specification</a>
  170. */
  171. public XPath createXPath(String str, ElemTemplateElement owningTemplate)
  172. throws javax.xml.transform.TransformerException
  173. {
  174. ErrorListener handler = m_stylesheetProcessor.getErrorListener();
  175. XPath xpath = new XPath(str, owningTemplate, this, XPath.SELECT, handler);
  176. // Visit the expression, registering namespaces for any extension functions it includes.
  177. xpath.callVisitors(xpath, new ExpressionVisitor(getStylesheetRoot()));
  178. return xpath;
  179. }
  180. /**
  181. * Process an expression string into an XPath.
  182. *
  183. * @param str A non-null reference to a valid or invalid match pattern string.
  184. *
  185. * @return A non-null reference to an XPath object that represents the string argument.
  186. *
  187. * @throws javax.xml.transform.TransformerException if the pattern can not be processed.
  188. * @see <a href="http://www.w3.org/TR/xslt#patterns">Section 5.2 Patterns in XSLT Specification</a>
  189. */
  190. XPath createMatchPatternXPath(String str, ElemTemplateElement owningTemplate)
  191. throws javax.xml.transform.TransformerException
  192. {
  193. ErrorListener handler = m_stylesheetProcessor.getErrorListener();
  194. XPath xpath = new XPath(str, owningTemplate, this, XPath.MATCH, handler);
  195. // Visit the expression, registering namespaces for any extension functions it includes.
  196. xpath.callVisitors(xpath, new ExpressionVisitor(getStylesheetRoot()));
  197. return xpath;
  198. }
  199. /**
  200. * Given a namespace, get the corrisponding prefix from the current
  201. * namespace support context.
  202. *
  203. * @param prefix The prefix to look up, which may be an empty string ("") for the default Namespace.
  204. *
  205. * @return The associated Namespace URI, or null if the prefix
  206. * is undeclared in this context.
  207. */
  208. public String getNamespaceForPrefix(String prefix)
  209. {
  210. return this.getNamespaceSupport().getURI(prefix);
  211. }
  212. /**
  213. * Given a namespace, get the corrisponding prefix. This is here only
  214. * to support the {@link org.apache.xml.utils.PrefixResolver} interface,
  215. * and will throw an error if invoked on this object.
  216. *
  217. * @param prefix The prefix to look up, which may be an empty string ("") for the default Namespace.
  218. * @param context The node context from which to look up the URI.
  219. *
  220. * @return The associated Namespace URI, or null if the prefix
  221. * is undeclared in this context.
  222. */
  223. public String getNamespaceForPrefix(String prefix, org.w3c.dom.Node context)
  224. {
  225. // Don't need to support this here. Return the current URI for the prefix,
  226. // ignoring the context.
  227. assertion(true, "can't process a context node in StylesheetHandler!");
  228. return null;
  229. }
  230. /**
  231. * Utility function to see if the stack contains the given URL.
  232. *
  233. * @param stack non-null reference to a Stack.
  234. * @param url URL string on which an equality test will be performed.
  235. *
  236. * @return true if the stack contains the url argument.
  237. */
  238. private boolean stackContains(Stack stack, String url)
  239. {
  240. int n = stack.size();
  241. boolean contains = false;
  242. for (int i = 0; i < n; i++)
  243. {
  244. String url2 = (String) stack.elementAt(i);
  245. if (url2.equals(url))
  246. {
  247. contains = true;
  248. break;
  249. }
  250. }
  251. return contains;
  252. }
  253. ////////////////////////////////////////////////////////////////////
  254. // Implementation of the TRAX TemplatesBuilder interface.
  255. ////////////////////////////////////////////////////////////////////
  256. /**
  257. * When this object is used as a ContentHandler or ContentHandler, it will
  258. * create a Templates object, which the caller can get once
  259. * the SAX events have been completed.
  260. * @return The stylesheet object that was created during
  261. * the SAX event process, or null if no stylesheet has
  262. * been created.
  263. *
  264. * @version Alpha
  265. * @author <a href="mailto:scott_boag@lotus.com">Scott Boag</a>
  266. */
  267. public Templates getTemplates()
  268. {
  269. return getStylesheetRoot();
  270. }
  271. /**
  272. * Set the base ID (URL or system ID) for the stylesheet
  273. * created by this builder. This must be set in order to
  274. * resolve relative URLs in the stylesheet.
  275. *
  276. * @param baseID Base URL for this stylesheet.
  277. */
  278. public void setSystemId(String baseID)
  279. {
  280. pushBaseIndentifier(baseID);
  281. }
  282. /**
  283. * Get the base ID (URI or system ID) from where relative
  284. * URLs will be resolved.
  285. *
  286. * @return The systemID that was set with {@link #setSystemId}.
  287. */
  288. public String getSystemId()
  289. {
  290. return this.getBaseIdentifier();
  291. }
  292. ////////////////////////////////////////////////////////////////////
  293. // Implementation of the EntityResolver interface.
  294. ////////////////////////////////////////////////////////////////////
  295. /**
  296. * Resolve an external entity.
  297. *
  298. * @param publicId The public identifer, or null if none is
  299. * available.
  300. * @param systemId The system identifier provided in the XML
  301. * document.
  302. * @return The new input source, or null to require the
  303. * default behaviour.
  304. *
  305. * @throws org.xml.sax.SAXException if the entity can not be resolved.
  306. */
  307. public InputSource resolveEntity(String publicId, String systemId)
  308. throws org.xml.sax.SAXException
  309. {
  310. return getCurrentProcessor().resolveEntity(this, publicId, systemId);
  311. }
  312. ////////////////////////////////////////////////////////////////////
  313. // Implementation of DTDHandler interface.
  314. ////////////////////////////////////////////////////////////////////
  315. /**
  316. * Receive notification of a notation declaration.
  317. *
  318. * <p>By default, do nothing. Application writers may override this
  319. * method in a subclass if they wish to keep track of the notations
  320. * declared in a document.</p>
  321. *
  322. * @param name The notation name.
  323. * @param publicId The notation public identifier, or null if not
  324. * available.
  325. * @param systemId The notation system identifier.
  326. * @see org.xml.sax.DTDHandler#notationDecl
  327. */
  328. public void notationDecl(String name, String publicId, String systemId)
  329. {
  330. getCurrentProcessor().notationDecl(this, name, publicId, systemId);
  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. * Given a namespace URI, and a local name or a node type, get the processor
  350. * for the element, or return null if not allowed.
  351. *
  352. * @param uri The Namespace URI, or an empty string.
  353. * @param localName The local name (without prefix), or empty string if not namespace processing.
  354. * @param rawName The qualified name (with prefix).
  355. *
  356. * @return A non-null reference to a element processor.
  357. *
  358. * @throws org.xml.sax.SAXException if the element is not allowed in the
  359. * found position in the stylesheet.
  360. */
  361. XSLTElementProcessor getProcessorFor(
  362. String uri, String localName, String rawName)
  363. throws org.xml.sax.SAXException
  364. {
  365. XSLTElementProcessor currentProcessor = getCurrentProcessor();
  366. XSLTElementDef def = currentProcessor.getElemDef();
  367. XSLTElementProcessor elemProcessor = def.getProcessorFor(uri, localName);
  368. if (null == elemProcessor
  369. && ((null == getStylesheet()
  370. || Double.valueOf(getStylesheet().getVersion()).doubleValue()
  371. > Constants.XSLTVERSUPPORTED)
  372. ||(!uri.equals(Constants.S_XSLNAMESPACEURL) &&
  373. currentProcessor instanceof ProcessorStylesheetElement)
  374. || getElemVersion() > Constants.XSLTVERSUPPORTED
  375. ))
  376. {
  377. elemProcessor = def.getProcessorForUnknown(uri, localName);
  378. }
  379. if (null == elemProcessor)
  380. error(XSLMessages.createMessage(XSLTErrorResources.ER_NOT_ALLOWED_IN_POSITION, new Object[]{rawName}),null);//rawName + " is not allowed in this position in the stylesheet!",
  381. return elemProcessor;
  382. }
  383. ////////////////////////////////////////////////////////////////////
  384. // Implementation of ContentHandler interface.
  385. ////////////////////////////////////////////////////////////////////
  386. /**
  387. * Receive a Locator object for document events.
  388. * This is called by the parser to push a locator for the
  389. * stylesheet being parsed. The stack needs to be popped
  390. * after the stylesheet has been parsed. We pop in
  391. * popStylesheet.
  392. *
  393. * @param locator A locator for all SAX document events.
  394. * @see org.xml.sax.ContentHandler#setDocumentLocator
  395. * @see org.xml.sax.Locator
  396. */
  397. public void setDocumentLocator(Locator locator)
  398. {
  399. // System.out.println("pushing locator for: "+locator.getSystemId());
  400. m_stylesheetLocatorStack.push(new SAXSourceLocator(locator));
  401. }
  402. /**
  403. * The level of the stylesheet we are at.
  404. */
  405. private int m_stylesheetLevel = -1;
  406. /**
  407. * Receive notification of the beginning of the document.
  408. *
  409. * @see org.xml.sax.ContentHandler#startDocument
  410. *
  411. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  412. * wrapping another exception.
  413. */
  414. public void startDocument() throws org.xml.sax.SAXException
  415. {
  416. m_stylesheetLevel++;
  417. pushSpaceHandling(false);
  418. }
  419. /** m_parsingComplete becomes true when the top-level stylesheet and all
  420. * its included/imported stylesheets have been been fully parsed, as an
  421. * indication that composition/optimization/compilation can begin.
  422. * @see isStylesheetParsingComplete */
  423. private boolean m_parsingComplete = false;
  424. /**
  425. * Test whether the _last_ endDocument() has been processed.
  426. * This is needed as guidance for stylesheet optimization
  427. * and compilation engines, which generally don't want to start
  428. * until all included and imported stylesheets have been fully
  429. * parsed.
  430. *
  431. * @return true iff the complete stylesheet tree has been built.
  432. */
  433. public boolean isStylesheetParsingComplete()
  434. {
  435. return m_parsingComplete;
  436. }
  437. /**
  438. * Receive notification of the end of the document.
  439. *
  440. * @see org.xml.sax.ContentHandler#endDocument
  441. *
  442. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  443. * wrapping another exception.
  444. */
  445. public void endDocument() throws org.xml.sax.SAXException
  446. {
  447. try
  448. {
  449. if (null != getStylesheetRoot())
  450. {
  451. if (0 == m_stylesheetLevel)
  452. getStylesheetRoot().recompose();
  453. }
  454. else
  455. throw new TransformerException(XSLMessages.createMessage(XSLTErrorResources.ER_NO_STYLESHEETROOT, null)); //"Did not find the stylesheet root!");
  456. XSLTElementProcessor elemProcessor = getCurrentProcessor();
  457. if (null != elemProcessor)
  458. elemProcessor.startNonText(this);
  459. m_stylesheetLevel--;
  460. popSpaceHandling();
  461. // WARNING: This test works only as long as stylesheets are parsed
  462. // more or less recursively. If we switch to an iterative "work-list"
  463. // model, this will become true prematurely. In that case,
  464. // isStylesheetParsingComplete() will have to be adjusted to be aware
  465. // of the worklist.
  466. m_parsingComplete = (m_stylesheetLevel < 0);
  467. }
  468. catch (TransformerException te)
  469. {
  470. throw new org.xml.sax.SAXException(te);
  471. }
  472. }
  473. private java.util.Vector m_prefixMappings = new java.util.Vector();
  474. /**
  475. * Receive notification of the start of a Namespace mapping.
  476. *
  477. * <p>By default, do nothing. Application writers may override this
  478. * method in a subclass to take specific actions at the start of
  479. * each element (such as allocating a new tree node or writing
  480. * output to a file).</p>
  481. *
  482. * @param prefix The Namespace prefix being declared.
  483. * @param uri The Namespace URI mapped to the prefix.
  484. * @see org.xml.sax.ContentHandler#startPrefixMapping
  485. *
  486. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  487. * wrapping another exception.
  488. */
  489. public void startPrefixMapping(String prefix, String uri)
  490. throws org.xml.sax.SAXException
  491. {
  492. // m_nsSupport.pushContext();
  493. // this.getNamespaceSupport().declarePrefix(prefix, uri);
  494. //m_prefixMappings.add(prefix); // JDK 1.2+ only -sc
  495. //m_prefixMappings.add(uri); // JDK 1.2+ only -sc
  496. m_prefixMappings.addElement(prefix); // JDK 1.1.x compat -sc
  497. m_prefixMappings.addElement(uri); // JDK 1.1.x compat -sc
  498. }
  499. /**
  500. * Receive notification of the end of a Namespace mapping.
  501. *
  502. * <p>By default, do nothing. Application writers may override this
  503. * method in a subclass to take specific actions at the start of
  504. * each element (such as allocating a new tree node or writing
  505. * output to a file).</p>
  506. *
  507. * @param prefix The Namespace prefix being declared.
  508. * @see org.xml.sax.ContentHandler#endPrefixMapping
  509. *
  510. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  511. * wrapping another exception.
  512. */
  513. public void endPrefixMapping(String prefix) throws org.xml.sax.SAXException
  514. {
  515. // m_nsSupport.popContext();
  516. }
  517. /**
  518. * Flush the characters buffer.
  519. *
  520. * @throws org.xml.sax.SAXException
  521. */
  522. private void flushCharacters() throws org.xml.sax.SAXException
  523. {
  524. XSLTElementProcessor elemProcessor = getCurrentProcessor();
  525. if (null != elemProcessor)
  526. elemProcessor.startNonText(this);
  527. }
  528. /**
  529. * Receive notification of the start of an element.
  530. *
  531. * @param name The element type name.
  532. *
  533. * @param uri The Namespace URI, or an empty string.
  534. * @param localName The local name (without prefix), or empty string if not namespace processing.
  535. * @param rawName The qualified name (with prefix).
  536. * @param attributes The specified or defaulted attributes.
  537. *
  538. * @throws org.xml.sax.SAXException
  539. */
  540. public void startElement(
  541. String uri, String localName, String rawName, Attributes attributes)
  542. throws org.xml.sax.SAXException
  543. {
  544. NamespaceSupport nssupport = this.getNamespaceSupport();
  545. nssupport.pushContext();
  546. int n = m_prefixMappings.size();
  547. for (int i = 0; i < n; i++)
  548. {
  549. String prefix = (String)m_prefixMappings.elementAt(i++);
  550. String nsURI = (String)m_prefixMappings.elementAt(i);
  551. nssupport.declarePrefix(prefix, nsURI);
  552. }
  553. //m_prefixMappings.clear(); // JDK 1.2+ only -sc
  554. m_prefixMappings.removeAllElements(); // JDK 1.1.x compat -sc
  555. m_elementID++;
  556. // This check is currently done for all elements. We should possibly consider
  557. // limiting this check to xsl:stylesheet elements only since that is all it really
  558. // applies to. Also, it could be bypassed if m_shouldProcess is already true.
  559. // In other words, the next two statements could instead look something like this:
  560. // if (!m_shouldProcess)
  561. // {
  562. // if (localName.equals(Constants.ELEMNAME_STYLESHEET_STRING) &&
  563. // url.equals(Constants.S_XSLNAMESPACEURL))
  564. // {
  565. // checkForFragmentID(attributes);
  566. // if (!m_shouldProcess)
  567. // return;
  568. // }
  569. // else
  570. // return;
  571. // }
  572. // I didn't include this code statement at this time because in practice
  573. // it is a small performance hit and I was waiting to see if its absence
  574. // caused a problem. - GLP
  575. checkForFragmentID(attributes);
  576. if (!m_shouldProcess)
  577. return;
  578. flushCharacters();
  579. pushSpaceHandling(attributes);
  580. XSLTElementProcessor elemProcessor = getProcessorFor(uri, localName,
  581. rawName);
  582. if(null != elemProcessor) // defensive, for better multiple error reporting. -sb
  583. {
  584. this.pushProcessor(elemProcessor);
  585. elemProcessor.startElement(this, uri, localName, rawName, attributes);
  586. }
  587. else
  588. {
  589. m_shouldProcess = false;
  590. popSpaceHandling();
  591. }
  592. }
  593. /**
  594. * Receive notification of the end of an element.
  595. *
  596. * @param name The element type name.
  597. * @param attributes The specified or defaulted attributes.
  598. *
  599. * @param uri The Namespace URI, or an empty string.
  600. * @param localName The local name (without prefix), or empty string if not namespace processing.
  601. * @param rawName The qualified name (with prefix).
  602. * @see org.xml.sax.ContentHandler#endElement
  603. *
  604. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  605. * wrapping another exception.
  606. */
  607. public void endElement(String uri, String localName, String rawName)
  608. throws org.xml.sax.SAXException
  609. {
  610. m_elementID--;
  611. if (!m_shouldProcess)
  612. return;
  613. if ((m_elementID + 1) == m_fragmentID)
  614. m_shouldProcess = false;
  615. flushCharacters();
  616. popSpaceHandling();
  617. XSLTElementProcessor p = getCurrentProcessor();
  618. p.endElement(this, uri, localName, rawName);
  619. this.popProcessor();
  620. this.getNamespaceSupport().popContext();
  621. }
  622. /**
  623. * Receive notification of character data inside an element.
  624. *
  625. * @param ch The characters.
  626. * @param start The start position in the character array.
  627. * @param length The number of characters to use from the
  628. * character array.
  629. * @see org.xml.sax.ContentHandler#characters
  630. *
  631. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  632. * wrapping another exception.
  633. */
  634. public void characters(char ch[], int start, int length)
  635. throws org.xml.sax.SAXException
  636. {
  637. if (!m_shouldProcess)
  638. return;
  639. XSLTElementProcessor elemProcessor = getCurrentProcessor();
  640. XSLTElementDef def = elemProcessor.getElemDef();
  641. if (def.getType() != XSLTElementDef.T_PCDATA)
  642. elemProcessor = def.getProcessorFor(null, "text()");
  643. if (null == elemProcessor)
  644. {
  645. // If it's whitespace, just ignore it, otherwise flag an error.
  646. if (!XMLCharacterRecognizer.isWhiteSpace(ch, start, length))
  647. error(
  648. XSLMessages.createMessage(XSLTErrorResources.ER_NONWHITESPACE_NOT_ALLOWED_IN_POSITION, null),null);//"Non-whitespace text is not allowed in this position in the stylesheet!",
  649. }
  650. else
  651. elemProcessor.characters(this, ch, start, length);
  652. }
  653. /**
  654. * Receive notification of ignorable whitespace in element content.
  655. *
  656. * @param ch The whitespace characters.
  657. * @param start The start position in the character array.
  658. * @param length The number of characters to use from the
  659. * character array.
  660. * @see org.xml.sax.ContentHandler#ignorableWhitespace
  661. *
  662. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  663. * wrapping another exception.
  664. */
  665. public void ignorableWhitespace(char ch[], int start, int length)
  666. throws org.xml.sax.SAXException
  667. {
  668. if (!m_shouldProcess)
  669. return;
  670. getCurrentProcessor().ignorableWhitespace(this, ch, start, length);
  671. }
  672. /**
  673. * Receive notification of a processing instruction.
  674. *
  675. * <p>The Parser will invoke this method once for each processing
  676. * instruction found: note that processing instructions may occur
  677. * before or after the main document element.</p>
  678. *
  679. * <p>A SAX parser should never report an XML declaration (XML 1.0,
  680. * section 2.8) or a text declaration (XML 1.0, section 4.3.1)
  681. * using this method.</p>
  682. *
  683. * <p>By default, do nothing. Application writers may override this
  684. * method in a subclass to take specific actions for each
  685. * processing instruction, such as setting status variables or
  686. * invoking other methods.</p>
  687. *
  688. * @param target The processing instruction target.
  689. * @param data The processing instruction data, or null if
  690. * none is supplied.
  691. * @see org.xml.sax.ContentHandler#processingInstruction
  692. *
  693. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  694. * wrapping another exception.
  695. */
  696. public void processingInstruction(String target, String data)
  697. throws org.xml.sax.SAXException
  698. {
  699. if (!m_shouldProcess)
  700. return;
  701. // Recreating Scott's kluge:
  702. // A xsl:for-each or xsl:apply-templates may have a special
  703. // PI that tells us not to cache the document. This PI
  704. // should really be namespaced.
  705. // String localName = getLocalName(target);
  706. // String ns = m_stylesheet.getNamespaceFromStack(target);
  707. //
  708. // %REVIEW%: We need a better PI architecture
  709. String prefix="",ns="", localName=target;
  710. int colon=target.indexOf(':');
  711. if(colon>=0)
  712. {
  713. ns=getNamespaceForPrefix(prefix=target.substring(0,colon));
  714. localName=target.substring(colon+1);
  715. }
  716. try
  717. {
  718. // A xsl:for-each or xsl:apply-templates may have a special
  719. // PI that tells us not to cache the document. This PI
  720. // should really be namespaced... but since the XML Namespaces
  721. // spec never defined namespaces as applying to PI's, and since
  722. // the testcase we're trying to support is inconsistant in whether
  723. // it binds the prefix, I'm going to make this sloppy for
  724. // testing purposes.
  725. if(
  726. "xalan:doc-cache-off".equals(target) ||
  727. ("doc-cache-off".equals(localName) &&
  728. ns.equals("org.apache.xalan.xslt.extensions.Redirect") )
  729. )
  730. {
  731. if(!(m_elems.peek() instanceof ElemForEach))
  732. throw new TransformerException
  733. ("xalan:doc-cache-off not allowed here!",
  734. getLocator());
  735. ElemForEach elem = (ElemForEach)m_elems.peek();
  736. elem.m_doc_cache_off = true;
  737. //System.out.println("JJK***** Recognized <? {"+ns+"}"+prefix+":"+localName+" "+data+"?>");
  738. }
  739. }
  740. catch(Exception e)
  741. {
  742. // JJK: Officially, unknown PIs can just be ignored.
  743. // Do we want to issue a warning?
  744. }
  745. flushCharacters();
  746. getCurrentProcessor().processingInstruction(this, target, data);
  747. }
  748. /**
  749. * Receive notification of a skipped entity.
  750. *
  751. * <p>By default, do nothing. Application writers may override this
  752. * method in a subclass to take specific actions for each
  753. * processing instruction, such as setting status variables or
  754. * invoking other methods.</p>
  755. *
  756. * @param name The name of the skipped entity.
  757. * @see org.xml.sax.ContentHandler#processingInstruction
  758. *
  759. * @throws org.xml.sax.SAXException Any SAX exception, possibly
  760. * wrapping another exception.
  761. */
  762. public void skippedEntity(String name) throws org.xml.sax.SAXException
  763. {
  764. if (!m_shouldProcess)
  765. return;
  766. getCurrentProcessor().skippedEntity(this, name);
  767. }
  768. /**
  769. * <meta name="usage" content="internal"/>
  770. * Warn the user of an problem.
  771. *
  772. * @param msg An key into the {@link org.apache.xalan.res.XSLTErrorResources}
  773. * table, that is one of the WG_ prefixed definitions.
  774. * @param args An array of arguments for the given warning.
  775. *
  776. * @throws org.xml.sax.SAXException that wraps a
  777. * {@link javax.xml.transform.TransformerException} if the current
  778. * {@link javax.xml.transform.ErrorListener#warning}
  779. * method chooses to flag this condition as an error.
  780. */
  781. public void warn(String msg, Object args[]) throws org.xml.sax.SAXException
  782. {
  783. String formattedMsg = m_XSLMessages.createWarning(msg, args);
  784. SAXSourceLocator locator = getLocator();
  785. ErrorListener handler = m_stylesheetProcessor.getErrorListener();
  786. try
  787. {
  788. if (null != handler)
  789. handler.warning(new TransformerException(formattedMsg, locator));
  790. }
  791. catch (TransformerException te)
  792. {
  793. throw new org.xml.sax.SAXException(te);
  794. }
  795. }
  796. /**
  797. * <meta name="usage" content="internal"/>
  798. * Assert that a condition is true. If it is not true, throw an error.
  799. *
  800. * @param condition false if an error should not be thrown, otherwise true.
  801. * @param msg Error message to be passed to the RuntimeException as an
  802. * argument.
  803. * @throws RuntimeException if the condition is not true.
  804. */
  805. private void assertion(boolean condition, String msg) throws RuntimeException
  806. {
  807. if (!condition)
  808. throw new RuntimeException(msg);
  809. }
  810. /**
  811. * <meta name="usage" content="internal"/>
  812. * Tell the user of an error, and probably throw an
  813. * exception.
  814. *
  815. * @param msg An error message.
  816. * @param e An error which the SAXException should wrap.
  817. *
  818. * @throws org.xml.sax.SAXException that wraps a
  819. * {@link javax.xml.transform.TransformerException} if the current
  820. * {@link javax.xml.transform.ErrorListener#error}
  821. * method chooses to flag this condition as an error.
  822. */
  823. protected void error(String msg, Exception e)
  824. throws org.xml.sax.SAXException
  825. {
  826. SAXSourceLocator locator = getLocator();
  827. ErrorListener handler = m_stylesheetProcessor.getErrorListener();
  828. TransformerException pe;
  829. if (!(e instanceof TransformerException))
  830. {
  831. pe = (null == e)
  832. ? new TransformerException(msg, locator)
  833. : new TransformerException(msg, locator, e);
  834. }
  835. else
  836. pe = (TransformerException) e;
  837. if (null != handler)
  838. {
  839. try
  840. {
  841. handler.error(pe);
  842. }
  843. catch (TransformerException te)
  844. {
  845. throw new org.xml.sax.SAXException(te);
  846. }
  847. }
  848. else
  849. throw new org.xml.sax.SAXException(pe);
  850. }
  851. /**
  852. * <meta name="usage" content="internal"/>
  853. * Tell the user of an error, and probably throw an
  854. * exception.
  855. *
  856. * @param msg A key into the {@link org.apache.xalan.res.XSLTErrorResources}
  857. * table, that is one of the WG_ prefixed definitions.
  858. * @param args An array of arguments for the given warning.
  859. * @param e An error which the SAXException should wrap.
  860. *
  861. * @throws org.xml.sax.SAXException that wraps a
  862. * {@link javax.xml.transform.TransformerException} if the current
  863. * {@link javax.xml.transform.ErrorListener#error}
  864. * method chooses to flag this condition as an error.
  865. */
  866. protected void error(String msg, Object args[], Exception e)
  867. throws org.xml.sax.SAXException
  868. {
  869. String formattedMsg = m_XSLMessages.createMessage(msg, args);
  870. error(formattedMsg, e);
  871. }
  872. /**
  873. * Receive notification of a XSLT processing warning.
  874. *
  875. * @param e The warning information encoded as an exception.
  876. *
  877. * @throws org.xml.sax.SAXException that wraps a
  878. * {@link javax.xml.transform.TransformerException} if the current
  879. * {@link javax.xml.transform.ErrorListener#warning}
  880. * method chooses to flag this condition as an error.
  881. */
  882. public void warning(org.xml.sax.SAXParseException e)
  883. throws org.xml.sax.SAXException
  884. {
  885. String formattedMsg = e.getMessage();
  886. SAXSourceLocator locator = getLocator();
  887. ErrorListener handler = m_stylesheetProcessor.getErrorListener();
  888. try
  889. {
  890. handler.warning(new TransformerException(formattedMsg, locator));
  891. }
  892. catch (TransformerException te)
  893. {
  894. throw new org.xml.sax.SAXException(te);
  895. }
  896. }
  897. /**
  898. * Receive notification of a recoverable XSLT processing error.
  899. *
  900. * @param e The error information encoded as an exception.
  901. *
  902. * @throws org.xml.sax.SAXException that wraps a
  903. * {@link javax.xml.transform.TransformerException} if the current
  904. * {@link javax.xml.transform.ErrorListener#error}
  905. * method chooses to flag this condition as an error.
  906. */
  907. public void error(org.xml.sax.SAXParseException e)
  908. throws org.xml.sax.SAXException
  909. {
  910. String formattedMsg = e.getMessage();
  911. SAXSourceLocator locator = getLocator();
  912. ErrorListener handler = m_stylesheetProcessor.getErrorListener();
  913. try
  914. {
  915. handler.error(new TransformerException(formattedMsg, locator));
  916. }
  917. catch (TransformerException te)
  918. {
  919. throw new org.xml.sax.SAXException(te);
  920. }
  921. }
  922. /**
  923. * Report a fatal XSLT processing error.
  924. *
  925. * @param e The error information encoded as an exception.
  926. *
  927. * @throws org.xml.sax.SAXException that wraps a
  928. * {@link javax.xml.transform.TransformerException} if the current
  929. * {@link javax.xml.transform.ErrorListener#fatalError}
  930. * method chooses to flag this condition as an error.
  931. */
  932. public void fatalError(org.xml.sax.SAXParseException e)
  933. throws org.xml.sax.SAXException
  934. {
  935. String formattedMsg = e.getMessage();
  936. SAXSourceLocator locator = getLocator();
  937. ErrorListener handler = m_stylesheetProcessor.getErrorListener();
  938. try
  939. {
  940. handler.fatalError(new TransformerException(formattedMsg, locator));
  941. }
  942. catch (TransformerException te)
  943. {
  944. throw new org.xml.sax.SAXException(te);
  945. }
  946. }
  947. /**
  948. * If we have a URL to a XML fragment, this is set
  949. * to false until the ID is found.
  950. * (warning: I worry that this should be in a stack).
  951. */
  952. private boolean m_shouldProcess = true;
  953. /**
  954. * If we have a URL to a XML fragment, the value is stored
  955. * in this string, and the m_shouldProcess flag is set to
  956. * false until we match an ID with this string.
  957. * (warning: I worry that this should be in a stack).
  958. */
  959. private String m_fragmentIDString;
  960. /**
  961. * Keep track of the elementID, so we can tell when
  962. * is has completed. This isn't a real ID, but rather
  963. * a nesting level. However, it's good enough for
  964. * our purposes.
  965. * (warning: I worry that this should be in a stack).
  966. */
  967. private int m_elementID = 0;
  968. /**
  969. * The ID of the fragment that has been found
  970. * (warning: I worry that this should be in a stack).
  971. */
  972. private int m_fragmentID = 0;
  973. /**
  974. * Check to see if an ID attribute matched the #id, called
  975. * from startElement.
  976. *
  977. * @param attributes The specified or defaulted attributes.
  978. */
  979. private void checkForFragmentID(Attributes attributes)
  980. {
  981. if (!m_shouldProcess)
  982. {
  983. if ((null != attributes) && (null != m_fragmentIDString))
  984. {
  985. int n = attributes.getLength();
  986. for (int i = 0; i < n; i++)
  987. {
  988. String name = attributes.getQName(i);
  989. if (name.equals(Constants.ATTRNAME_ID))
  990. {
  991. String val = attributes.getValue(i);
  992. if (val.equalsIgnoreCase(m_fragmentIDString))
  993. {
  994. m_shouldProcess = true;
  995. m_fragmentID = m_elementID;
  996. }
  997. }
  998. }
  999. }
  1000. }
  1001. }
  1002. /**
  1003. * The XSLT TransformerFactory for needed services.
  1004. */
  1005. private TransformerFactoryImpl m_stylesheetProcessor;
  1006. /**
  1007. * Get the XSLT TransformerFactoryImpl for needed services.
  1008. * TODO: This method should be renamed.
  1009. *
  1010. * @return The TransformerFactoryImpl that owns this handler.
  1011. */
  1012. TransformerFactoryImpl getStylesheetProcessor()
  1013. {
  1014. return m_stylesheetProcessor;
  1015. }
  1016. /**
  1017. * If {@link #getStylesheetType} returns this value, the current stylesheet
  1018. * is a root stylesheet.
  1019. */
  1020. static final int STYPE_ROOT = 1;
  1021. /**
  1022. * If {@link #getStylesheetType} returns this value, the current stylesheet
  1023. * is an included stylesheet.
  1024. */
  1025. static final int STYPE_INCLUDE = 2;
  1026. /**
  1027. * If {@link #getStylesheetType} returns this value, the current stylesheet
  1028. * is an imported stylesheet.
  1029. */
  1030. static final int STYPE_IMPORT = 3;
  1031. /** The current stylesheet type. */
  1032. private int m_stylesheetType = STYPE_ROOT;
  1033. /**
  1034. * Get the type of stylesheet that should be built
  1035. * or is being processed.
  1036. *
  1037. * @return one of STYPE_ROOT, STYPE_INCLUDE, or STYPE_IMPORT.
  1038. */
  1039. int getStylesheetType()
  1040. {
  1041. return m_stylesheetType;
  1042. }
  1043. /**
  1044. * Set the type of stylesheet that should be built
  1045. * or is being processed.
  1046. *
  1047. * @param type Must be one of STYPE_ROOT, STYPE_INCLUDE, or STYPE_IMPORT.
  1048. */
  1049. void setStylesheetType(int type)
  1050. {
  1051. m_stylesheetType = type;
  1052. }
  1053. /**
  1054. * The stack of stylesheets being processed.
  1055. */
  1056. private Stack m_stylesheets = new Stack();
  1057. /**
  1058. * Return the stylesheet that this handler is constructing.
  1059. *
  1060. * @return The current stylesheet that is on top of the stylesheets stack,
  1061. * or null if no stylesheet is on the stylesheets stack.
  1062. */
  1063. Stylesheet getStylesheet()
  1064. {
  1065. return (m_stylesheets.size() == 0)
  1066. ? null : (Stylesheet) m_stylesheets.peek();
  1067. }
  1068. /**
  1069. * Return the last stylesheet that was popped off the stylesheets stack.
  1070. *
  1071. * @return The last popped stylesheet, or null.
  1072. */
  1073. Stylesheet getLastPoppedStylesheet()
  1074. {
  1075. return m_lastPoppedStylesheet;
  1076. }
  1077. /**
  1078. * Return the stylesheet root that this handler is constructing.
  1079. *
  1080. * @return The root stylesheet of the stylesheets tree.
  1081. */
  1082. public StylesheetRoot getStylesheetRoot()
  1083. {
  1084. return m_stylesheetRoot;
  1085. }
  1086. /** The root stylesheet of the stylesheets tree. */
  1087. StylesheetRoot m_stylesheetRoot;
  1088. /** The last stylesheet that was popped off the stylesheets stack. */
  1089. Stylesheet m_lastPoppedStylesheet;
  1090. /**
  1091. * Push the current stylesheet being constructed. If no other stylesheets
  1092. * have been pushed onto the stack, assume the argument is a stylesheet
  1093. * root, and also set the stylesheet root member.
  1094. *
  1095. * @param s non-null reference to a stylesheet.
  1096. */
  1097. public void pushStylesheet(Stylesheet s)
  1098. {
  1099. if (m_stylesheets.size() == 0)
  1100. m_stylesheetRoot = (StylesheetRoot) s;
  1101. m_stylesheets.push(s);
  1102. }
  1103. /**
  1104. * Pop the last stylesheet pushed, and return the stylesheet that this
  1105. * handler is constructing, and set the last popped stylesheet member.
  1106. * Also pop the stylesheet locator stack.
  1107. *
  1108. * @return The stylesheet popped off the stack, or the last popped stylesheet.
  1109. */
  1110. Stylesheet popStylesheet()
  1111. {
  1112. // The stylesheetLocatorStack needs to be popped because
  1113. // a locator was pushed in for this stylesheet by the SAXparser by calling
  1114. // setDocumentLocator().
  1115. if (!m_stylesheetLocatorStack.isEmpty())
  1116. m_stylesheetLocatorStack.pop();
  1117. if (!m_stylesheets.isEmpty())
  1118. m_lastPoppedStylesheet = (Stylesheet) m_stylesheets.pop();
  1119. // Shouldn't this be null if stylesheets is empty? -sb
  1120. return m_lastPoppedStylesheet;
  1121. }
  1122. /**
  1123. * The stack of current processors.
  1124. */
  1125. private Stack m_processors = new Stack();
  1126. /**
  1127. * Get the current XSLTElementProcessor at the top of the stack.
  1128. *
  1129. * @return Valid XSLTElementProcessor, which should never be null.
  1130. */
  1131. XSLTElementProcessor getCurrentProcessor()
  1132. {
  1133. return (XSLTElementProcessor) m_processors.peek();
  1134. }
  1135. /**
  1136. * Push the current XSLTElementProcessor onto the top of the stack.
  1137. *
  1138. * @param processor non-null reference to the current element processor.
  1139. */
  1140. void pushProcessor(XSLTElementProcessor processor)
  1141. {
  1142. m_processors.push(processor);
  1143. }
  1144. /**
  1145. * Pop the current XSLTElementProcessor from the top of the stack.
  1146. * @return the XSLTElementProcessor which was popped.
  1147. */
  1148. XSLTElementProcessor popProcessor()
  1149. {
  1150. return (XSLTElementProcessor) m_processors.pop();
  1151. }
  1152. /**
  1153. * The root of the XSLT Schema, which tells us how to
  1154. * transition content handlers, create elements, etc.
  1155. * For the moment at least, this can't be static, since
  1156. * the processors store state.
  1157. */
  1158. private XSLTSchema m_schema = new XSLTSchema();
  1159. /**
  1160. * Get the root of the XSLT Schema, which tells us how to
  1161. * transition content handlers, create elements, etc.
  1162. *
  1163. * @return The root XSLT Schema, which should never be null.
  1164. */
  1165. XSLTSchema getSchema()
  1166. {
  1167. return m_schema;
  1168. }
  1169. /**
  1170. * The stack of elements, pushed and popped as events occur.
  1171. */
  1172. private Stack m_elems = new Stack();
  1173. /**
  1174. * Get the current ElemTemplateElement at the top of the stack.
  1175. * @return Valid ElemTemplateElement, which may be null.
  1176. */
  1177. ElemTemplateElement getElemTemplateElement()
  1178. {
  1179. try
  1180. {
  1181. return (ElemTemplateElement) m_elems.peek();
  1182. }
  1183. catch (java.util.EmptyStackException ese)
  1184. {
  1185. return null;
  1186. }
  1187. }
  1188. /** An increasing number that is used to indicate the order in which this element
  1189. * was encountered during the parse of the XSLT tree.
  1190. */
  1191. private int m_docOrderCount = 0;
  1192. /**
  1193. * Returns the next m_docOrderCount number and increments the number for future use.
  1194. */
  1195. int nextUid()
  1196. {
  1197. return m_docOrderCount++;
  1198. }
  1199. /**
  1200. * Push the current XSLTElementProcessor to the top of the stack. As a
  1201. * side-effect, set the document order index (simply because this is a
  1202. * convenient place to set it).
  1203. *
  1204. * @param elem Should be a non-null reference to the intended current
  1205. * template element.
  1206. */
  1207. void pushElemTemplateElement(ElemTemplateElement elem)
  1208. {
  1209. if (elem.getUid() == -1)
  1210. elem.setUid(nextUid());
  1211. m_elems.push(elem);
  1212. }
  1213. /**
  1214. * Get the current XSLTElementProcessor from the top of the stack.
  1215. * @return the ElemTemplateElement which was popped.
  1216. */
  1217. ElemTemplateElement popElemTemplateElement()
  1218. {
  1219. return (ElemTemplateElement) m_elems.pop();
  1220. }
  1221. /**
  1222. * A XSLMessages instance capable of producing user messages.
  1223. */
  1224. private static XSLMessages m_XSLMessages = new XSLMessages();
  1225. /**
  1226. * Get an XSLMessages instance capable of producing user messages.
  1227. *
  1228. * @return non-null reference to the error and warnings table.
  1229. */
  1230. XSLMessages getXSLMessages()
  1231. {
  1232. return m_XSLMessages;
  1233. }
  1234. /**
  1235. * This will act as a stack to keep track of the
  1236. * current include base.
  1237. */
  1238. Stack m_baseIdentifiers = new Stack();
  1239. /**
  1240. * Push a base identifier onto the base URI stack.
  1241. *
  1242. * @param baseID The current base identifier for this position in the
  1243. * stylesheet, which may be a fragment identifier, or which may be null.
  1244. * @see <a href="http://www.w3.org/TR/xslt#base-uri">
  1245. * Section 3.2 Base URI of XSLT specification.</a>
  1246. */
  1247. void pushBaseIndentifier(String baseID)
  1248. {
  1249. if (null != baseID)
  1250. {
  1251. int posOfHash = baseID.indexOf('#');
  1252. if (posOfHash > -1)
  1253. {
  1254. m_fragmentIDString = baseID.substring(posOfHash + 1);
  1255. m_shouldProcess = false;
  1256. }
  1257. else
  1258. m_shouldProcess = true;
  1259. }
  1260. else
  1261. m_shouldProcess = true;
  1262. m_baseIdentifiers.push(baseID);
  1263. }
  1264. /**
  1265. * Pop a base URI from the stack.
  1266. * @return baseIdentifier.
  1267. */
  1268. String popBaseIndentifier()
  1269. {
  1270. return (String) m_baseIdentifiers.pop();
  1271. }
  1272. /**
  1273. * Return the base identifier.
  1274. *
  1275. * @return The base identifier of the current stylesheet.
  1276. */
  1277. public String getBaseIdentifier()
  1278. {
  1279. // Try to get the baseIdentifier from the baseIdentifier's stack,
  1280. // which may not be the same thing as the value found in the
  1281. // SourceLocators stack.
  1282. String base = (String) (m_baseIdentifiers.isEmpty()
  1283. ? null : m_baseIdentifiers.peek());
  1284. // Otherwise try the stylesheet.
  1285. if (null == base)
  1286. {
  1287. SourceLocator locator = getLocator();
  1288. base = (null == locator) ? "" : locator.getSystemId();
  1289. }
  1290. return base;
  1291. }
  1292. /**
  1293. * The top of this stack should contain the currently processed
  1294. * stylesheet SAX locator object.
  1295. */
  1296. private Stack m_stylesheetLocatorStack = new Stack();
  1297. /**
  1298. * Get the current stylesheet Locator object.
  1299. *
  1300. * @return non-null reference to the current locator object.
  1301. */
  1302. public SAXSourceLocator getLocator()
  1303. {
  1304. if (m_stylesheetLocatorStack.isEmpty())
  1305. {
  1306. SAXSourceLocator locator = new SAXSourceLocator();
  1307. locator.setSystemId(this.getStylesheetProcessor().getDOMsystemID());
  1308. return locator;
  1309. // m_stylesheetLocatorStack.push(locator);
  1310. }
  1311. return ((SAXSourceLocator) m_stylesheetLocatorStack.peek());
  1312. }
  1313. /**
  1314. * A stack of URL hrefs for imported stylesheets. This is
  1315. * used to diagnose circular imports.
  1316. */
  1317. private Stack m_importStack = new Stack();
  1318. /**
  1319. * Push an import href onto the stylesheet stack.
  1320. *
  1321. * @param hrefUrl non-null reference to the URL for the current imported
  1322. * stylesheet.
  1323. */
  1324. void pushImportURL(String hrefUrl)
  1325. {
  1326. m_importStack.push(hrefUrl);
  1327. }
  1328. /**
  1329. * See if the imported stylesheet stack already contains
  1330. * the given URL. Used to test for recursive imports.
  1331. *
  1332. * @param hrefUrl non-null reference to a URL string.
  1333. *
  1334. * @return true if the URL is on the import stack.
  1335. */
  1336. boolean importStackContains(String hrefUrl)
  1337. {
  1338. return stackContains(m_importStack, hrefUrl);
  1339. }
  1340. /**
  1341. * Pop an import href from the stylesheet stack.
  1342. *
  1343. * @return non-null reference to the import URL that was popped.
  1344. */
  1345. String popImportURL()
  1346. {
  1347. return (String) m_importStack.pop();
  1348. }
  1349. /**
  1350. * If this is set to true, we've already warned about using the
  1351. * older XSLT namespace URL.
  1352. */
  1353. private boolean warnedAboutOldXSLTNamespace = false;
  1354. /** Stack of NamespaceSupport objects. */
  1355. Stack m_nsSupportStack = new Stack();
  1356. /**
  1357. * Push a new NamespaceSupport instance.
  1358. */
  1359. void pushNewNamespaceSupport()
  1360. {
  1361. m_nsSupportStack.push(new NamespaceSupport2());
  1362. }
  1363. /**
  1364. * Pop the current NamespaceSupport object.
  1365. *
  1366. */
  1367. void popNamespaceSupport()
  1368. {
  1369. m_nsSupportStack.pop();
  1370. }
  1371. /**
  1372. * Get the current NamespaceSupport object.
  1373. *
  1374. * @return a non-null reference to the current NamespaceSupport object,
  1375. * which is the top of the namespace support stack.
  1376. */
  1377. NamespaceSupport getNamespaceSupport()
  1378. {
  1379. return (NamespaceSupport) m_nsSupportStack.peek();
  1380. }
  1381. /**
  1382. * The originating node if the current stylesheet is being created
  1383. * from a DOM.
  1384. * @see org.apache.xml.utils.NodeConsumer
  1385. */
  1386. private Node m_originatingNode;
  1387. /**
  1388. * Set the node that is originating the SAX event.
  1389. *
  1390. * @param n Reference to node that originated the current event.
  1391. * @see org.apache.xml.utils.NodeConsumer
  1392. */
  1393. public void setOriginatingNode(Node n)
  1394. {
  1395. m_originatingNode = n;
  1396. }
  1397. /**
  1398. * Set the node that is originating the SAX event.
  1399. *
  1400. * @return Reference to node that originated the current event.
  1401. * @see org.apache.xml.utils.NodeConsumer
  1402. */
  1403. public Node getOriginatingNode()
  1404. {
  1405. return m_originatingNode;
  1406. }
  1407. /**
  1408. * Stack of booleans that are pushed and popped in start/endElement depending
  1409. * on the value of xml:space=default/preserve.
  1410. */
  1411. private BoolStack m_spacePreserveStack = new BoolStack();
  1412. /**
  1413. * Return boolean value from the spacePreserve stack depending on the value
  1414. * of xml:space=default/preserve.
  1415. *
  1416. * @return true if space should be preserved, false otherwise.
  1417. */
  1418. boolean isSpacePreserve()
  1419. {
  1420. return m_spacePreserveStack.peek();
  1421. }
  1422. /**
  1423. * Pop boolean value from the spacePreserve stack.
  1424. */
  1425. void popSpaceHandling()
  1426. {
  1427. m_spacePreserveStack.pop();
  1428. }
  1429. /**
  1430. * Push boolean value on to the spacePreserve stack.
  1431. *
  1432. * @param b true if space should be preserved, false otherwise.
  1433. */
  1434. void pushSpaceHandling(boolean b)
  1435. throws org.xml.sax.SAXParseException
  1436. {
  1437. m_spacePreserveStack.push(b);
  1438. }
  1439. /**
  1440. * Push boolean value on to the spacePreserve stack depending on the value
  1441. * of xml:space=default/preserve.
  1442. *
  1443. * @param attrs list of attributes that were passed to startElement.
  1444. */
  1445. void pushSpaceHandling(Attributes attrs)
  1446. throws org.xml.sax.SAXParseException
  1447. {
  1448. String value = attrs.getValue("xml:space");
  1449. if(null == value)
  1450. {
  1451. m_spacePreserveStack.push(m_spacePreserveStack.peekOrFalse());
  1452. }
  1453. else if(value.equals("preserve"))
  1454. {
  1455. m_spacePreserveStack.push(true);
  1456. }
  1457. else if(value.equals("default"))
  1458. {
  1459. m_spacePreserveStack.push(false);
  1460. }
  1461. else
  1462. {
  1463. SAXSourceLocator locator = getLocator();
  1464. ErrorListener handler = m_stylesheetProcessor.getErrorListener();
  1465. try
  1466. {
  1467. handler.error(new TransformerException(XSLMessages.createMessage(XSLTErrorResources.ER_ILLEGAL_XMLSPACE_VALUE, null), locator)); //"Illegal value for xml:space", locator));
  1468. }
  1469. catch (TransformerException te)
  1470. {
  1471. throw new org.xml.sax.SAXParseException(te.getMessage(), locator, te);
  1472. }
  1473. m_spacePreserveStack.push(m_spacePreserveStack.peek());
  1474. }
  1475. }
  1476. private double getElemVersion()
  1477. {
  1478. ElemTemplateElement elem = getElemTemplateElement();
  1479. double version = -1;
  1480. while ((version == -1 || version == Constants.XSLTVERSUPPORTED) && elem != null)
  1481. {
  1482. try{
  1483. version = Double.valueOf(elem.getVersion()).doubleValue();
  1484. }
  1485. catch (Exception ex)
  1486. {
  1487. version = -1;
  1488. }
  1489. elem = elem.getParentElem();
  1490. }
  1491. return (version == -1)? Constants.XSLTVERSUPPORTED : version;
  1492. }
  1493. /**
  1494. * @see PrefixResolver#handlesNullPrefixes()
  1495. */
  1496. public boolean handlesNullPrefixes() {
  1497. return false;
  1498. }
  1499. }