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.templates;
  58. // import org.w3c.dom.*;
  59. import org.apache.xml.dtm.DTM;
  60. import java.util.*;
  61. import java.net.MalformedURLException;
  62. import java.text.DecimalFormat;
  63. import java.text.DecimalFormatSymbols;
  64. import java.io.*;
  65. import org.xml.sax.*;
  66. import org.xml.sax.helpers.*;
  67. import org.apache.xalan.serialize.*;
  68. import org.apache.xml.utils.*;
  69. import org.apache.xpath.*;
  70. import org.apache.xpath.compiler.XPathParser;
  71. import org.apache.xalan.trace.*;
  72. import org.apache.xalan.res.XSLTErrorResources;
  73. import org.apache.xalan.res.XSLMessages;
  74. import org.apache.xalan.processor.XSLTSchema;
  75. import org.apache.xalan.transformer.TransformerImpl;
  76. import javax.xml.transform.Transformer;
  77. import javax.xml.transform.TransformerException;
  78. import javax.xml.transform.TransformerConfigurationException;
  79. import javax.xml.transform.Templates;
  80. import javax.xml.transform.OutputKeys;
  81. import javax.xml.transform.ErrorListener;
  82. import org.apache.xml.dtm.ref.ExpandedNameTable;
  83. //dml
  84. import org.apache.xml.utils.StringVector;
  85. import org.apache.xalan.extensions.ExtensionNamespaceSupport;
  86. import org.apache.xalan.extensions.ExtensionHandler;
  87. import org.apache.xalan.extensions.ExtensionNamespacesManager;
  88. /**
  89. * <meta name="usage" content="general"/>
  90. * This class represents the root object of the stylesheet tree.
  91. */
  92. public class StylesheetRoot extends StylesheetComposed
  93. implements java.io.Serializable, Templates
  94. {
  95. /**
  96. * Uses an XSL stylesheet document.
  97. * @throws TransformerConfigurationException if the baseIdentifier can not be resolved to a URL.
  98. */
  99. public StylesheetRoot(ErrorListener errorListener) throws TransformerConfigurationException
  100. {
  101. super(null);
  102. setStylesheetRoot(this);
  103. try
  104. {
  105. m_selectDefault = new XPath("node()", this, this, XPath.SELECT, errorListener);
  106. initDefaultRule(errorListener);
  107. }
  108. catch (TransformerException se)
  109. {
  110. throw new TransformerConfigurationException(XSLMessages.createMessage(XSLTErrorResources.ER_CANNOT_INIT_DEFAULT_TEMPLATES, null), se); //"Can't init default templates!", se);
  111. }
  112. }
  113. /**
  114. * The schema used when creating this StylesheetRoot
  115. * @serial
  116. */
  117. private Hashtable m_availElems;
  118. /**
  119. * Creates a StylesheetRoot and retains a pointer to the schema used to create this
  120. * StylesheetRoot. The schema may be needed later for an element-available() function call.
  121. *
  122. * @param schema The schema used to create this stylesheet
  123. * @throws TransformerConfigurationException if the baseIdentifier can not be resolved to a URL.
  124. */
  125. public StylesheetRoot(XSLTSchema schema, ErrorListener listener) throws TransformerConfigurationException
  126. {
  127. this(listener);
  128. m_availElems = schema.getElemsAvailable();
  129. }
  130. /**
  131. * Tell if this is the root of the stylesheet tree.
  132. *
  133. * @return True since this is the root of the stylesheet tree.
  134. */
  135. public boolean isRoot()
  136. {
  137. return true;
  138. }
  139. /**
  140. * Get the hashtable of available elements.
  141. *
  142. * @return table of available elements, keyed by qualified names, and with
  143. * values of the same qualified names.
  144. */
  145. public Hashtable getAvailableElements()
  146. {
  147. return m_availElems;
  148. }
  149. private ExtensionNamespacesManager m_extNsMgr = null;
  150. /**
  151. * Only instantiate an ExtensionNamespacesManager if one is called for
  152. * (i.e., if the stylesheet contains extension functions and/or elements).
  153. */
  154. public ExtensionNamespacesManager getExtensionNamespacesManager()
  155. {
  156. if (m_extNsMgr == null)
  157. m_extNsMgr = new ExtensionNamespacesManager();
  158. return m_extNsMgr;
  159. }
  160. /**
  161. * Get the vector of extension namespaces. Used to provide
  162. * the extensions table access to a list of extension
  163. * namespaces encountered during composition of a stylesheet.
  164. */
  165. public Vector getExtensions()
  166. {
  167. return m_extNsMgr != null ? m_extNsMgr.getExtensions() : null;
  168. }
  169. /*
  170. public void runtimeInit(TransformerImpl transformer) throws TransformerException
  171. {
  172. System.out.println("StylesheetRoot.runtimeInit()");
  173. // try{throw new Exception("StylesheetRoot.runtimeInit()");} catch(Exception e){e.printStackTrace();}
  174. }
  175. */
  176. //============== Templates Interface ================
  177. /**
  178. * Create a new transformation context for this Templates object.
  179. *
  180. * @return A Transformer instance, never null.
  181. */
  182. public Transformer newTransformer()
  183. {
  184. return new TransformerImpl(this);
  185. }
  186. public Properties getDefaultOutputProps()
  187. {
  188. return m_outputProperties.getProperties();
  189. }
  190. /**
  191. * Get the static properties for xsl:output. The object returned will
  192. * be a clone of the internal values, and thus it can be mutated
  193. * without mutating the Templates object, and then handed in to
  194. * the process method.
  195. *
  196. * <p>For XSLT, Attribute Value Templates attribute values will
  197. * be returned unexpanded (since there is no context at this point).</p>
  198. *
  199. * @return A Properties object, not null.
  200. */
  201. public Properties getOutputProperties()
  202. {
  203. return (Properties)getDefaultOutputProps().clone();
  204. }
  205. //============== End Templates Interface ================
  206. /**
  207. * Recompose the values of all "composed" properties, meaning
  208. * properties that need to be combined or calculated from
  209. * the combination of imported and included stylesheets. This
  210. * method determines the proper import precedence of all imported
  211. * stylesheets. It then iterates through all of the elements and
  212. * properties in the proper order and triggers the individual recompose
  213. * methods.
  214. *
  215. * @throws TransformerException
  216. */
  217. public void recompose() throws TransformerException
  218. {
  219. // Now we make a Vector that is going to hold all of the recomposable elements
  220. Vector recomposableElements = new Vector();
  221. // First, we build the global import tree.
  222. if (null == m_globalImportList)
  223. {
  224. Vector importList = new Vector();
  225. addImports(this, true, importList);
  226. // Now we create an array and reverse the order of the importList vector.
  227. // We built the importList vector backwards so that we could use addElement
  228. // to append to the end of the vector instead of constantly pushing new
  229. // stylesheets onto the front of the vector and having to shift the rest
  230. // of the vector each time.
  231. m_globalImportList = new StylesheetComposed[importList.size()];
  232. for (int i = 0, j= importList.size() -1; i < importList.size(); i++)
  233. {
  234. m_globalImportList[j] = (StylesheetComposed) importList.elementAt(i);
  235. // Build the global include list for this stylesheet.
  236. // This needs to be done ahead of the recomposeImports
  237. // because we need the info from the composed includes.
  238. m_globalImportList[j].recomposeIncludes(m_globalImportList[j]);
  239. // Calculate the number of this import.
  240. m_globalImportList[j--].recomposeImports();
  241. }
  242. }
  243. // Next, we walk the import tree and add all of the recomposable elements to the vector.
  244. int n = getGlobalImportCount();
  245. for (int i = 0; i < n; i++)
  246. {
  247. StylesheetComposed imported = getGlobalImport(i);
  248. imported.recompose(recomposableElements);
  249. }
  250. // We sort the elements into ascending order.
  251. QuickSort2(recomposableElements, 0, recomposableElements.size() - 1);
  252. // We set up the global variables that will hold the recomposed information.
  253. m_outputProperties = new OutputProperties(Method.XML);
  254. m_attrSets = new Hashtable();
  255. m_decimalFormatSymbols = new Hashtable();
  256. m_keyDecls = new Vector();
  257. m_namespaceAliasComposed = new Hashtable();
  258. m_templateList = new TemplateList();
  259. m_variables = new Vector();
  260. // Now we sequence through the sorted elements,
  261. // calling the recompose() function on each one. This will call back into the
  262. // appropriate routine here to actually do the recomposition.
  263. // Note that we're going backwards, encountering the highest precedence items first.
  264. for (int i = recomposableElements.size() - 1; i >= 0; i--)
  265. ((ElemTemplateElement) recomposableElements.elementAt(i)).recompose(this);
  266. initComposeState();
  267. // Need final composition of TemplateList. This adds the wild cards onto the chains.
  268. m_templateList.compose(this);
  269. // Need to clear check for properties at the same import level.
  270. m_outputProperties.compose(this);
  271. m_outputProperties.endCompose(this);
  272. // Now call the compose() method on every element to give it a chance to adjust
  273. // based on composed values.
  274. n = getGlobalImportCount();
  275. for (int i = 0; i < n; i++)
  276. {
  277. StylesheetComposed imported = this.getGlobalImport(i);
  278. int includedCount = imported.getIncludeCountComposed();
  279. for (int j = -1; j < includedCount; j++)
  280. {
  281. Stylesheet included = imported.getIncludeComposed(j);
  282. composeTemplates(included);
  283. }
  284. }
  285. // Attempt to register any remaining unregistered extension namespaces.
  286. if (m_extNsMgr != null)
  287. m_extNsMgr.registerUnregisteredNamespaces();
  288. clearComposeState();
  289. }
  290. /**
  291. * Call the compose function for each ElemTemplateElement.
  292. *
  293. * @param templ non-null reference to template element that will have
  294. * the composed method called on it, and will have it's children's composed
  295. * methods called.
  296. */
  297. void composeTemplates(ElemTemplateElement templ) throws TransformerException
  298. {
  299. templ.compose(this);
  300. for (ElemTemplateElement child = templ.getFirstChildElem();
  301. child != null; child = child.getNextSiblingElem())
  302. {
  303. composeTemplates(child);
  304. }
  305. templ.endCompose(this);
  306. }
  307. /**
  308. * The combined list of imports. The stylesheet with the highest
  309. * import precedence will be at element 0. The one with the lowest
  310. * import precedence will be at element length - 1.
  311. * @serial
  312. */
  313. private StylesheetComposed[] m_globalImportList;
  314. /**
  315. * Add the imports in the given sheet to the working importList vector.
  316. * The will be added from highest import precedence to
  317. * least import precedence. This is a post-order traversal of the
  318. * import tree as described in <a href="http://www.w3.org/TR/xslt.html#import">the
  319. * XSLT Recommendation</a>.
  320. * <p>For example, suppose</p>
  321. * <p>stylesheet A imports stylesheets B and C in that order;</p>
  322. * <p>stylesheet B imports stylesheet D;</p>
  323. * <p>stylesheet C imports stylesheet E.</p>
  324. * <p>Then the order of import precedence (highest first) is
  325. * A, C, E, B, D.</p>
  326. *
  327. * @param stylesheet Stylesheet to examine for imports.
  328. * @param addToList <code>true</code> if this template should be added to the import list
  329. * @param importList The working import list. Templates are added here in the reverse
  330. * order of priority. When we're all done, we'll reverse this to the correct
  331. * priority in an array.
  332. */
  333. protected void addImports(Stylesheet stylesheet, boolean addToList, Vector importList)
  334. {
  335. // Get the direct imports of this sheet.
  336. int n = stylesheet.getImportCount();
  337. if (n > 0)
  338. {
  339. for (int i = 0; i < n; i++)
  340. {
  341. Stylesheet imported = stylesheet.getImport(i);
  342. addImports(imported, true, importList);
  343. }
  344. }
  345. n = stylesheet.getIncludeCount();
  346. if (n > 0)
  347. {
  348. for (int i = 0; i < n; i++)
  349. {
  350. Stylesheet included = stylesheet.getInclude(i);
  351. addImports(included, false, importList);
  352. }
  353. }
  354. if (addToList)
  355. importList.addElement(stylesheet);
  356. }
  357. /**
  358. * Get a stylesheet from the global import list.
  359. * TODO: JKESS PROPOSES SPECIAL-CASE FOR NO IMPORT LIST, TO MATCH COUNT.
  360. *
  361. * @param i Index of stylesheet to get from global import list
  362. *
  363. * @return The stylesheet at the given index
  364. */
  365. public StylesheetComposed getGlobalImport(int i)
  366. {
  367. return m_globalImportList[i];
  368. }
  369. /**
  370. * Get the total number of imports in the global import list.
  371. *
  372. * @return The total number of imported stylesheets, including
  373. * the root stylesheet, thus the number will always be 1 or
  374. * greater.
  375. * TODO: JKESS PROPOSES SPECIAL-CASE FOR NO IMPORT LIST, TO MATCH DESCRIPTION.
  376. */
  377. public int getGlobalImportCount()
  378. {
  379. return (m_globalImportList!=null)
  380. ? m_globalImportList.length
  381. : 1;
  382. }
  383. /**
  384. * Given a stylesheet, return the number of the stylesheet
  385. * in the global import list.
  386. * @param sheet The stylesheet which will be located in the
  387. * global import list.
  388. * @return The index into the global import list of the given stylesheet,
  389. * or -1 if it is not found (which should never happen).
  390. */
  391. public int getImportNumber(StylesheetComposed sheet)
  392. {
  393. if (this == sheet)
  394. return 0;
  395. int n = getGlobalImportCount();
  396. for (int i = 0; i < n; i++)
  397. {
  398. if (sheet == getGlobalImport(i))
  399. return i;
  400. }
  401. return -1;
  402. }
  403. /**
  404. * This will be set up with the default values, and then the values
  405. * will be set as stylesheets are encountered.
  406. * @serial
  407. */
  408. private OutputProperties m_outputProperties;
  409. /**
  410. * Recompose the output format object from the included elements.
  411. *
  412. * @param oprops non-null reference to xsl:output properties representation.
  413. */
  414. void recomposeOutput(OutputProperties oprops)
  415. throws TransformerException
  416. {
  417. m_outputProperties.copyFrom(oprops);
  418. }
  419. /**
  420. * Get the combined "xsl:output" property with the properties
  421. * combined from the included stylesheets. If a xsl:output
  422. * is not declared in this stylesheet or an included stylesheet,
  423. * look in the imports.
  424. * Please note that this returns a reference to the OutputProperties
  425. * object, not a cloned object, like getOutputProperties does.
  426. * @see <a href="http://www.w3.org/TR/xslt#output">output in XSLT Specification</a>
  427. *
  428. * @return non-null reference to composed output properties object.
  429. */
  430. public OutputProperties getOutputComposed()
  431. {
  432. // System.out.println("getOutputComposed.getIndent: "+m_outputProperties.getIndent());
  433. // System.out.println("getOutputComposed.getIndenting: "+m_outputProperties.getIndenting());
  434. return m_outputProperties;
  435. }
  436. /** Flag indicating whether an output method has been set by the user.
  437. * @serial */
  438. private boolean m_outputMethodSet = false;
  439. /**
  440. * <meta name="usage" content="internal"/>
  441. * Find out if an output method has been set by the user.
  442. *
  443. * @return Value indicating whether an output method has been set by the user
  444. */
  445. public boolean isOutputMethodSet()
  446. {
  447. return m_outputMethodSet;
  448. }
  449. /**
  450. * Composed set of all included and imported attribute set properties.
  451. * Each entry is a vector of ElemAttributeSet objects.
  452. * @serial
  453. */
  454. private Hashtable m_attrSets;
  455. /**
  456. * Recompose the attribute-set declarations.
  457. *
  458. * @param attrSet An attribute-set to add to the hashtable of attribute sets.
  459. */
  460. void recomposeAttributeSets(ElemAttributeSet attrSet)
  461. {
  462. Vector attrSetList = (Vector) m_attrSets.get(attrSet.getName());
  463. if (null == attrSetList)
  464. {
  465. attrSetList = new Vector();
  466. m_attrSets.put(attrSet.getName(), attrSetList);
  467. }
  468. attrSetList.addElement(attrSet);
  469. }
  470. /**
  471. * Get a list "xsl:attribute-set" properties that match the qname.
  472. * @see <a href="http://www.w3.org/TR/xslt#attribute-sets">attribute-sets in XSLT Specification</a>
  473. *
  474. * @param name Qualified name of attribute set properties to get
  475. *
  476. * @return A vector of attribute sets matching the given name
  477. *
  478. * @throws ArrayIndexOutOfBoundsException
  479. */
  480. public Vector getAttributeSetComposed(QName name)
  481. throws ArrayIndexOutOfBoundsException
  482. {
  483. return (Vector) m_attrSets.get(name);
  484. }
  485. /**
  486. * Table of DecimalFormatSymbols, keyed by QName.
  487. * @serial
  488. */
  489. private Hashtable m_decimalFormatSymbols;
  490. /**
  491. * Recompose the decimal-format declarations.
  492. *
  493. * @param dfp A DecimalFormatProperties to add to the hashtable of decimal formats.
  494. */
  495. void recomposeDecimalFormats(DecimalFormatProperties dfp)
  496. {
  497. DecimalFormatSymbols oldDfs =
  498. (DecimalFormatSymbols) m_decimalFormatSymbols.get(dfp.getName());
  499. if (null == oldDfs)
  500. {
  501. m_decimalFormatSymbols.put(dfp.getName(), dfp.getDecimalFormatSymbols());
  502. }
  503. else if (!dfp.getDecimalFormatSymbols().equals(oldDfs))
  504. {
  505. String themsg;
  506. if (dfp.getName().equals(new QName("")))
  507. {
  508. // "Only one default xsl:decimal-format declaration is allowed."
  509. themsg = XSLMessages.createWarning(
  510. XSLTErrorResources.WG_ONE_DEFAULT_XSLDECIMALFORMAT_ALLOWED,
  511. new Object[0]);
  512. }
  513. else
  514. {
  515. // "xsl:decimal-format names must be unique. Name {0} has been duplicated."
  516. themsg = XSLMessages.createWarning(
  517. XSLTErrorResources.WG_XSLDECIMALFORMAT_NAMES_MUST_BE_UNIQUE,
  518. new Object[] {dfp.getName()});
  519. }
  520. error(themsg); // Should we throw TransformerException instead?
  521. }
  522. }
  523. /**
  524. * Given a valid element decimal-format name, return the
  525. * decimalFormatSymbols with that name.
  526. * <p>It is an error to declare either the default decimal-format or
  527. * a decimal-format with a given name more than once (even with
  528. * different import precedence), unless it is declared every
  529. * time with the same value for all attributes (taking into
  530. * account any default values).</p>
  531. * <p>Which means, as far as I can tell, the decimal-format
  532. * properties are not additive.</p>
  533. *
  534. * @param name Qualified name of the decimal format to find
  535. * @return DecimalFormatSymbols object matching the given name or
  536. * null if name is not found.
  537. */
  538. public DecimalFormatSymbols getDecimalFormatComposed(QName name)
  539. {
  540. return (DecimalFormatSymbols) m_decimalFormatSymbols.get(name);
  541. }
  542. /**
  543. * A list of all key declarations visible from this stylesheet and all
  544. * lesser stylesheets.
  545. * @serial
  546. */
  547. private Vector m_keyDecls;
  548. /**
  549. * Recompose the key declarations.
  550. *
  551. * @param keyDecl A KeyDeclaration to be added to the vector of key declarations.
  552. */
  553. void recomposeKeys(KeyDeclaration keyDecl)
  554. {
  555. m_keyDecls.addElement(keyDecl);
  556. }
  557. /**
  558. * Get the composed "xsl:key" properties.
  559. * @see <a href="http://www.w3.org/TR/xslt#key">key in XSLT Specification</a>
  560. *
  561. * @return A vector of the composed "xsl:key" properties.
  562. */
  563. public Vector getKeysComposed()
  564. {
  565. return m_keyDecls;
  566. }
  567. /**
  568. * Composed set of all namespace aliases.
  569. * @serial
  570. */
  571. private Hashtable m_namespaceAliasComposed;
  572. /**
  573. * Recompose the namespace-alias declarations.
  574. *
  575. * @param nsAlias A NamespaceAlias object to add to the hashtable of namespace aliases.
  576. */
  577. void recomposeNamespaceAliases(NamespaceAlias nsAlias)
  578. {
  579. m_namespaceAliasComposed.put(nsAlias.getStylesheetNamespace(),
  580. nsAlias);
  581. }
  582. /**
  583. * Get the "xsl:namespace-alias" property.
  584. * Return the NamespaceAlias for a given namespace uri.
  585. * @see <a href="http://www.w3.org/TR/xslt#literal-result-element">literal-result-element in XSLT Specification</a>
  586. *
  587. * @param uri non-null reference to namespace that is to be aliased.
  588. *
  589. * @return NamespaceAlias that matches uri, or null if no match.
  590. */
  591. public NamespaceAlias getNamespaceAliasComposed(String uri)
  592. {
  593. return (NamespaceAlias) ((null == m_namespaceAliasComposed)
  594. ? null : m_namespaceAliasComposed.get(uri));
  595. }
  596. /**
  597. * The "xsl:template" properties.
  598. * @serial
  599. */
  600. private TemplateList m_templateList;
  601. /**
  602. * Recompose the template declarations.
  603. *
  604. * @param template An ElemTemplate object to add to the template list.
  605. */
  606. void recomposeTemplates(ElemTemplate template)
  607. {
  608. m_templateList.setTemplate(template);
  609. }
  610. /**
  611. * Accessor method to retrieve the <code>TemplateList</code> associated with
  612. * this StylesheetRoot.
  613. *
  614. * @return The composed <code>TemplateList</code>.
  615. */
  616. public final TemplateList getTemplateListComposed()
  617. {
  618. return m_templateList;
  619. }
  620. /**
  621. * Mutator method to set the <code>TemplateList</code> associated with this
  622. * StylesheetRoot. This method should only be used by the compiler. Normally,
  623. * the template list is built during the recompose process and should not be
  624. * altered by the user.
  625. * @param templateList The new <code>TemplateList</code> for this StylesheetRoot.
  626. */
  627. public final void setTemplateListComposed(TemplateList templateList)
  628. {
  629. m_templateList = templateList;
  630. }
  631. /**
  632. * Get an "xsl:template" property by node match. This looks in the imports as
  633. * well as this stylesheet.
  634. * @see <a href="http://www.w3.org/TR/xslt#section-Defining-Template-Rules">section-Defining-Template-Rules in XSLT Specification</a>
  635. *
  636. * @param xctxt non-null reference to XPath runtime execution context.
  637. * @param targetNode non-null reference of node that the template must match.
  638. * @param mode qualified name of the node, or null.
  639. * @param quietConflictWarnings true if conflict warnings should not be reported.
  640. *
  641. * @return reference to ElemTemplate that is the best match for targetNode, or
  642. * null if no match could be made.
  643. *
  644. * @throws TransformerException
  645. */
  646. public ElemTemplate getTemplateComposed(XPathContext xctxt,
  647. int targetNode,
  648. QName mode,
  649. boolean quietConflictWarnings,
  650. DTM dtm)
  651. throws TransformerException
  652. {
  653. return m_templateList.getTemplate(xctxt, targetNode, mode,
  654. quietConflictWarnings,
  655. dtm);
  656. }
  657. /**
  658. * Get an "xsl:template" property by node match. This looks in the imports as
  659. * well as this stylesheet.
  660. * @see <a href="http://www.w3.org/TR/xslt#section-Defining-Template-Rules">section-Defining-Template-Rules in XSLT Specification</a>
  661. *
  662. * @param xctxt non-null reference to XPath runtime execution context.
  663. * @param targetNode non-null reference of node that the template must match.
  664. * @param mode qualified name of the node, or null.
  665. * @param maxImportLevel The maximum importCountComposed that we should consider or -1
  666. * if we should consider all import levels. This is used by apply-imports to
  667. * access templates that have been overridden.
  668. * @param endImportLevel The count of composed imports
  669. * @param quietConflictWarnings true if conflict warnings should not be reported.
  670. *
  671. * @return reference to ElemTemplate that is the best match for targetNode, or
  672. * null if no match could be made.
  673. *
  674. * @throws TransformerException
  675. */
  676. public ElemTemplate getTemplateComposed(XPathContext xctxt,
  677. int targetNode,
  678. QName mode,
  679. int maxImportLevel, int endImportLevel,
  680. boolean quietConflictWarnings,
  681. DTM dtm)
  682. throws TransformerException
  683. {
  684. return m_templateList.getTemplate(xctxt, targetNode, mode,
  685. maxImportLevel, endImportLevel,
  686. quietConflictWarnings,
  687. dtm);
  688. }
  689. /**
  690. * Get an "xsl:template" property. This looks in the imports as
  691. * well as this stylesheet.
  692. * @see <a href="http://www.w3.org/TR/xslt#section-Defining-Template-Rules">section-Defining-Template-Rules in XSLT Specification</a>
  693. *
  694. * @param qname non-null reference to qualified name of template.
  695. *
  696. * @return reference to named template, or null if not found.
  697. */
  698. public ElemTemplate getTemplateComposed(QName qname)
  699. {
  700. return m_templateList.getTemplate(qname);
  701. }
  702. /**
  703. * Composed set of all variables and params.
  704. * @serial
  705. */
  706. private Vector m_variables;
  707. /**
  708. * Recompose the top level variable and parameter declarations.
  709. *
  710. * @param elemVar A top level variable or parameter to be added to the Vector.
  711. */
  712. void recomposeVariables(ElemVariable elemVar)
  713. {
  714. // Don't overide higher priority variable
  715. if (getVariableOrParamComposed(elemVar.getName()) == null)
  716. {
  717. elemVar.setIsTopLevel(true); // Mark as a top-level variable or param
  718. elemVar.setIndex(m_variables.size());
  719. m_variables.addElement(elemVar);
  720. }
  721. }
  722. /**
  723. * Get an "xsl:variable" property.
  724. * @see <a href="http://www.w3.org/TR/xslt#top-level-variables">top-level-variables in XSLT Specification</a>
  725. *
  726. * @param qname Qualified name of variable or param
  727. *
  728. * @return The ElemVariable with the given qualified name
  729. */
  730. public ElemVariable getVariableOrParamComposed(QName qname)
  731. {
  732. if (null != m_variables)
  733. {
  734. int n = m_variables.size();
  735. for (int i = 0; i < n; i++)
  736. {
  737. ElemVariable var = (ElemVariable)m_variables.elementAt(i);
  738. if(var.getName().equals(qname))
  739. return var;
  740. }
  741. }
  742. return null;
  743. }
  744. /**
  745. * Get all global "xsl:variable" properties in scope for this stylesheet.
  746. * @see <a href="http://www.w3.org/TR/xslt#top-level-variables">top-level-variables in XSLT Specification</a>
  747. *
  748. * @return Vector of all variables and params in scope
  749. */
  750. public Vector getVariablesAndParamsComposed()
  751. {
  752. return m_variables;
  753. }
  754. /**
  755. * A list of properties that specify how to do space
  756. * stripping. This uses the same exact mechanism as Templates.
  757. * @serial
  758. */
  759. private TemplateList m_whiteSpaceInfoList;
  760. /**
  761. * Recompose the strip-space and preserve-space declarations.
  762. *
  763. * @param wsi A WhiteSpaceInfo element to add to the list of WhiteSpaceInfo elements.
  764. */
  765. void recomposeWhiteSpaceInfo(WhiteSpaceInfo wsi)
  766. {
  767. if (null == m_whiteSpaceInfoList)
  768. m_whiteSpaceInfoList = new TemplateList();
  769. m_whiteSpaceInfoList.setTemplate(wsi);
  770. }
  771. /**
  772. * Check to see if the caller should bother with check for
  773. * whitespace nodes.
  774. *
  775. * @return Whether the caller should bother with check for
  776. * whitespace nodes.
  777. */
  778. public boolean shouldCheckWhitespace()
  779. {
  780. return null != m_whiteSpaceInfoList;
  781. }
  782. /**
  783. * Get information about whether or not an element should strip whitespace.
  784. * @see <a href="http://www.w3.org/TR/xslt#strip">strip in XSLT Specification</a>
  785. *
  786. * @param support The XPath runtime state.
  787. * @param targetElement Element to check
  788. *
  789. * @return WhiteSpaceInfo for the given element
  790. *
  791. * @throws TransformerException
  792. */
  793. public WhiteSpaceInfo getWhiteSpaceInfo(
  794. XPathContext support, int targetElement, DTM dtm) throws TransformerException
  795. {
  796. if (null != m_whiteSpaceInfoList)
  797. return (WhiteSpaceInfo) m_whiteSpaceInfoList.getTemplate(support,
  798. targetElement, null, false, dtm);
  799. else
  800. return null;
  801. }
  802. /**
  803. * Get information about whether or not an element should strip whitespace.
  804. * @see <a href="http://www.w3.org/TR/xslt#strip">strip in XSLT Specification</a>
  805. *
  806. * @param support The XPath runtime state.
  807. * @param targetElement Element to check
  808. *
  809. * @return true if the whitespace should be stripped.
  810. *
  811. * @throws TransformerException
  812. */
  813. public boolean shouldStripWhiteSpace(
  814. XPathContext support, int targetElement) throws TransformerException
  815. {
  816. if (null != m_whiteSpaceInfoList)
  817. {
  818. while(DTM.NULL != targetElement)
  819. {
  820. DTM dtm = support.getDTM(targetElement);
  821. WhiteSpaceInfo info = (WhiteSpaceInfo) m_whiteSpaceInfoList.getTemplate(support,
  822. targetElement, null, false, dtm);
  823. if(null != info)
  824. return info.getShouldStripSpace();
  825. int parent = dtm.getParent(targetElement);
  826. if(DTM.NULL != parent && DTM.ELEMENT_NODE == dtm.getNodeType(parent))
  827. targetElement = parent;
  828. else
  829. targetElement = DTM.NULL;
  830. }
  831. }
  832. return false;
  833. }
  834. /**
  835. * Get information about whether or not whitespace can be stripped.
  836. * @see <a href="http://www.w3.org/TR/xslt#strip">strip in XSLT Specification</a>
  837. *
  838. * @return true if the whitespace can be stripped.
  839. */
  840. public boolean canStripWhiteSpace()
  841. {
  842. return (null != m_whiteSpaceInfoList);
  843. }
  844. /**
  845. * <meta name="usage" content="advanced"/>
  846. * The default template to use for text nodes if we don't find
  847. * anything else. This is initialized in initDefaultRule().
  848. * @serial
  849. */
  850. private ElemTemplate m_defaultTextRule;
  851. /**
  852. * <meta name="usage" content="advanced"/>
  853. * Get the default template for text.
  854. *
  855. * @return the default template for text.
  856. */
  857. public final ElemTemplate getDefaultTextRule()
  858. {
  859. return m_defaultTextRule;
  860. }
  861. /**
  862. * <meta name="usage" content="advanced"/>
  863. * The default template to use if we don't find anything
  864. * else. This is initialized in initDefaultRule().
  865. * @serial
  866. */
  867. private ElemTemplate m_defaultRule;
  868. /**
  869. * <meta name="usage" content="advanced"/>
  870. * Get the default template for elements.
  871. *
  872. * @return the default template for elements.
  873. */
  874. public final ElemTemplate getDefaultRule()
  875. {
  876. return m_defaultRule;
  877. }
  878. /**
  879. * <meta name="usage" content="advanced"/>
  880. * The default template to use for the root if we don't find
  881. * anything else. This is initialized in initDefaultRule().
  882. * We kind of need this because the defaultRule isn't good
  883. * enough because it doesn't supply a document context.
  884. * For now, I default the root document element to "HTML".
  885. * Don't know if this is really a good idea or not.
  886. * I suspect it is not.
  887. * @serial
  888. */
  889. private ElemTemplate m_defaultRootRule;
  890. /**
  891. * <meta name="usage" content="advanced"/>
  892. * Get the default template for a root node.
  893. *
  894. * @return The default template for a root node.
  895. */
  896. public final ElemTemplate getDefaultRootRule()
  897. {
  898. return m_defaultRootRule;
  899. }
  900. /**
  901. * <meta name="usage" content="advanced"/>
  902. * The start rule to kick off the transformation.
  903. * @serial
  904. */
  905. private ElemTemplate m_startRule;
  906. /**
  907. * <meta name="usage" content="advanced"/>
  908. * Get the default template for a root node.
  909. *
  910. * @return The default template for a root node.
  911. */
  912. public final ElemTemplate getStartRule()
  913. {
  914. return m_startRule;
  915. }
  916. /**
  917. * Used for default selection.
  918. * @serial
  919. */
  920. XPath m_selectDefault;
  921. /**
  922. * Create the default rule if needed.
  923. *
  924. * @throws TransformerException
  925. */
  926. private void initDefaultRule(ErrorListener errorListener) throws TransformerException
  927. {
  928. // Then manufacture a default
  929. m_defaultRule = new ElemTemplate();
  930. m_defaultRule.setStylesheet(this);
  931. XPath defMatch = new XPath("*", this, this, XPath.MATCH, errorListener);
  932. m_defaultRule.setMatch(defMatch);
  933. ElemApplyTemplates childrenElement = new ElemApplyTemplates();
  934. childrenElement.setIsDefaultTemplate(true);
  935. childrenElement.setSelect(m_selectDefault);
  936. m_defaultRule.appendChild(childrenElement);
  937. m_startRule = m_defaultRule;
  938. // -----------------------------
  939. m_defaultTextRule = new ElemTemplate();
  940. m_defaultTextRule.setStylesheet(this);
  941. defMatch = new XPath("text() | @*", this, this, XPath.MATCH, errorListener);
  942. m_defaultTextRule.setMatch(defMatch);
  943. ElemValueOf elemValueOf = new ElemValueOf();
  944. m_defaultTextRule.appendChild(elemValueOf);
  945. XPath selectPattern = new XPath(".", this, this, XPath.SELECT, errorListener);
  946. elemValueOf.setSelect(selectPattern);
  947. //--------------------------------
  948. m_defaultRootRule = new ElemTemplate();
  949. m_defaultRootRule.setStylesheet(this);
  950. defMatch = new XPath("/", this, this, XPath.MATCH, errorListener);
  951. m_defaultRootRule.setMatch(defMatch);
  952. childrenElement = new ElemApplyTemplates();
  953. childrenElement.setIsDefaultTemplate(true);
  954. m_defaultRootRule.appendChild(childrenElement);
  955. childrenElement.setSelect(m_selectDefault);
  956. }
  957. /**
  958. * This is a generic version of C.A.R Hoare's Quick Sort
  959. * algorithm. This will handle arrays that are already
  960. * sorted, and arrays with duplicate keys. It was lifted from
  961. * the NodeSorter class but should probably be eliminated and replaced
  962. * with a call to Collections.sort when we migrate to Java2.<BR>
  963. *
  964. * If you think of a one dimensional array as going from
  965. * the lowest index on the left to the highest index on the right
  966. * then the parameters to this function are lowest index or
  967. * left and highest index or right. The first time you call
  968. * this function it will be with the parameters 0, a.length - 1.
  969. *
  970. * @param v a vector of ElemTemplateElement elements
  971. * @param lo0 left boundary of partition
  972. * @param hi0 right boundary of partition
  973. *
  974. */
  975. private void QuickSort2(Vector v, int lo0, int hi0)
  976. {
  977. int lo = lo0;
  978. int hi = hi0;
  979. if ( hi0 > lo0)
  980. {
  981. // Arbitrarily establishing partition element as the midpoint of
  982. // the array.
  983. ElemTemplateElement midNode = (ElemTemplateElement) v.elementAt( ( lo0 + hi0 ) / 2 );
  984. // loop through the array until indices cross
  985. while( lo <= hi )
  986. {
  987. // find the first element that is greater than or equal to
  988. // the partition element starting from the left Index.
  989. while( (lo < hi0) && (((ElemTemplateElement) v.elementAt(lo)).compareTo(midNode) < 0) )
  990. {
  991. ++lo;
  992. } // end while
  993. // find an element that is smaller than or equal to
  994. // the partition element starting from the right Index.
  995. while( (hi > lo0) && (((ElemTemplateElement) v.elementAt(hi)).compareTo(midNode) > 0) ) {
  996. --hi;
  997. }
  998. // if the indexes have not crossed, swap
  999. if( lo <= hi )
  1000. {
  1001. ElemTemplateElement node = (ElemTemplateElement) v.elementAt(lo);
  1002. v.setElementAt(v.elementAt(hi), lo);
  1003. v.setElementAt(node, hi);
  1004. ++lo;
  1005. --hi;
  1006. }
  1007. }
  1008. // If the right index has not reached the left side of array
  1009. // must now sort the left partition.
  1010. if( lo0 < hi )
  1011. {
  1012. QuickSort2( v, lo0, hi );
  1013. }
  1014. // If the left index has not reached the right side of array
  1015. // must now sort the right partition.
  1016. if( lo < hi0 )
  1017. {
  1018. QuickSort2( v, lo, hi0 );
  1019. }
  1020. }
  1021. } // end QuickSort2 */
  1022. private ComposeState m_composeState;
  1023. /**
  1024. * Initialize a new ComposeState.
  1025. */
  1026. void initComposeState()
  1027. {
  1028. m_composeState = new ComposeState();
  1029. }
  1030. /**
  1031. * Return class to track state global state during the compose() operation.
  1032. * @return ComposeState reference, or null if endCompose has been called.
  1033. */
  1034. ComposeState getComposeState()
  1035. {
  1036. return m_composeState;
  1037. }
  1038. /**
  1039. * Clear the compose state.
  1040. */
  1041. private void clearComposeState()
  1042. {
  1043. m_composeState = null;
  1044. }
  1045. /**
  1046. * Class to track state global state during the compose() operation.
  1047. */
  1048. class ComposeState
  1049. {
  1050. ComposeState()
  1051. {
  1052. int size = m_variables.size();
  1053. for (int i = 0; i < size; i++)
  1054. {
  1055. ElemVariable ev = (ElemVariable)m_variables.elementAt(i);
  1056. m_variableNames.addElement(ev.getName());
  1057. }
  1058. }
  1059. private ExpandedNameTable m_ent = new ExpandedNameTable();
  1060. /**
  1061. * Given a qualified name, return an integer ID that can be
  1062. * quickly compared.
  1063. *
  1064. * @param qname a qualified name object, must not be null.
  1065. *
  1066. * @return the expanded-name id of the qualified name.
  1067. */
  1068. public int getQNameID(QName qname)
  1069. {
  1070. return m_ent.getExpandedTypeID(qname.getNamespace(),
  1071. qname.getLocalName(),
  1072. // The type doesn't matter for our
  1073. // purposes.
  1074. org.apache.xml.dtm.DTM.ELEMENT_NODE);
  1075. }
  1076. /**
  1077. * A Vector of the current params and QNames within the current template.
  1078. * Set by ElemTemplate and used by ProcessorVariable.
  1079. */
  1080. private java.util.Vector m_variableNames = new java.util.Vector();
  1081. /**
  1082. * Add the name of a qualified name within the template. The position in
  1083. * the vector is its ID.
  1084. * @param qname A qualified name of a param or variable, should be non-null.
  1085. * @return the index where the variable was added.
  1086. */
  1087. int addVariableName(final org.apache.xml.utils.QName qname)
  1088. {
  1089. int pos = m_variableNames.size();
  1090. m_variableNames.addElement(qname);
  1091. int frameSize = m_variableNames.size() - getGlobalsSize();
  1092. if(frameSize > m_maxStackFrameSize)
  1093. m_maxStackFrameSize++;
  1094. return pos;
  1095. }
  1096. void resetStackFrameSize()
  1097. {
  1098. m_maxStackFrameSize = 0;
  1099. }
  1100. int getFrameSize()
  1101. {
  1102. return m_maxStackFrameSize;
  1103. }
  1104. /**
  1105. * Get the current size of the stack frame. Use this to record the position
  1106. * in a template element at startElement, so that it can be popped
  1107. * at endElement.
  1108. */
  1109. int getCurrentStackFrameSize()
  1110. {
  1111. return m_variableNames.size();
  1112. }
  1113. /**
  1114. * Set the current size of the stack frame.
  1115. */
  1116. void setCurrentStackFrameSize(int sz)
  1117. {
  1118. m_variableNames.setSize(sz);
  1119. }
  1120. int getGlobalsSize()
  1121. {
  1122. return m_variables.size();
  1123. }
  1124. IntStack m_marks = new IntStack();
  1125. void pushStackMark()
  1126. {
  1127. m_marks.push(getCurrentStackFrameSize());
  1128. }
  1129. void popStackMark()
  1130. {
  1131. int mark = m_marks.pop();
  1132. setCurrentStackFrameSize(mark);
  1133. }
  1134. /**
  1135. * Get the Vector of the current params and QNames to be collected
  1136. * within the current template.
  1137. * @return A reference to the vector of variable names. The reference
  1138. * returned is owned by this class, and so should not really be mutated, or
  1139. * stored anywhere.
  1140. */
  1141. java.util.Vector getVariableNames()
  1142. {
  1143. return m_variableNames;
  1144. }
  1145. private int m_maxStackFrameSize;
  1146. }
  1147. }