/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * $Id: StylesheetRoot.java 476466 2006-11-18 08:22:31Z minchau $ */ package org.apache.xalan.templates; import java.text.DecimalFormatSymbols; import java.util.ArrayList; import java.util.HashMap; import java.util.Hashtable; import java.util.Properties; import java.util.Vector; import javax.xml.transform.ErrorListener; import javax.xml.transform.Templates; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import org.apache.xalan.extensions.ExtensionNamespacesManager; import org.apache.xalan.processor.XSLTSchema; import org.apache.xalan.res.XSLMessages; import org.apache.xalan.res.XSLTErrorResources; import org.apache.xalan.transformer.TransformerImpl; import org.apache.xml.dtm.DTM; import org.apache.xml.dtm.ref.ExpandedNameTable; import org.apache.xml.utils.IntStack; import org.apache.xml.utils.QName; import org.apache.xpath.XPath; import org.apache.xpath.XPathContext; /** * This class represents the root object of the stylesheet tree. * @xsl.usage general */ public class StylesheetRoot extends StylesheetComposed implements java.io.Serializable, Templates { static final long serialVersionUID = 3875353123529147855L; /** * The flag for the setting of the optimize feature; */ private boolean m_optimizer = true; /** * The flag for the setting of the incremental feature; */ private boolean m_incremental = false; /** * The flag for the setting of the source_location feature; */ private boolean m_source_location = false; /** * State of the secure processing feature. */ private boolean m_isSecureProcessing = false; /** * Uses an XSL stylesheet document. * @throws TransformerConfigurationException if the baseIdentifier can not be resolved to a URL. */ public StylesheetRoot(ErrorListener errorListener) throws TransformerConfigurationException { super(null); setStylesheetRoot(this); try { m_selectDefault = new XPath("node()", this, this, XPath.SELECT, errorListener); initDefaultRule(errorListener); } catch (TransformerException se) { throw new TransformerConfigurationException(XSLMessages.createMessage(XSLTErrorResources.ER_CANNOT_INIT_DEFAULT_TEMPLATES, null), se); //"Can't init default templates!", se); } } /** * The schema used when creating this StylesheetRoot * @serial */ private HashMap m_availElems; /** * Creates a StylesheetRoot and retains a pointer to the schema used to create this * StylesheetRoot. The schema may be needed later for an element-available() function call. * * @param schema The schema used to create this stylesheet * @throws TransformerConfigurationException if the baseIdentifier can not be resolved to a URL. */ public StylesheetRoot(XSLTSchema schema, ErrorListener listener) throws TransformerConfigurationException { this(listener); m_availElems = schema.getElemsAvailable(); } /** * Tell if this is the root of the stylesheet tree. * * @return True since this is the root of the stylesheet tree. */ public boolean isRoot() { return true; } /** * Set the state of the secure processing feature. */ public void setSecureProcessing(boolean flag) { m_isSecureProcessing = flag; } /** * Return the state of the secure processing feature. */ public boolean isSecureProcessing() { return m_isSecureProcessing; } /** * Get the hashtable of available elements. * * @return table of available elements, keyed by qualified names, and with * values of the same qualified names. */ public HashMap getAvailableElements() { return m_availElems; } private transient ExtensionNamespacesManager m_extNsMgr = null; /** * Only instantiate an ExtensionNamespacesManager if one is called for * (i.e., if the stylesheet contains extension functions and/or elements). */ public ExtensionNamespacesManager getExtensionNamespacesManager() { if (m_extNsMgr == null) m_extNsMgr = new ExtensionNamespacesManager(); return m_extNsMgr; } /** * Get the vector of extension namespaces. Used to provide * the extensions table access to a list of extension * namespaces encountered during composition of a stylesheet. */ public Vector getExtensions() { return m_extNsMgr != null ? m_extNsMgr.getExtensions() : null; } /* public void runtimeInit(TransformerImpl transformer) throws TransformerException { System.out.println("StylesheetRoot.runtimeInit()"); // try{throw new Exception("StylesheetRoot.runtimeInit()");} catch(Exception e){e.printStackTrace();} } */ //============== Templates Interface ================ /** * Create a new transformation context for this Templates object. * * @return A Transformer instance, never null. */ public Transformer newTransformer() { return new TransformerImpl(this); } public Properties getDefaultOutputProps() { return m_outputProperties.getProperties(); } /** * Get the static properties for xsl:output. The object returned will * be a clone of the internal values, and thus it can be mutated * without mutating the Templates object, and then handed in to * the process method. * *

For XSLT, Attribute Value Templates attribute values will * be returned unexpanded (since there is no context at this point).

* * @return A Properties object, not null. */ public Properties getOutputProperties() { return (Properties)getDefaultOutputProps().clone(); } //============== End Templates Interface ================ /** * Recompose the values of all "composed" properties, meaning * properties that need to be combined or calculated from * the combination of imported and included stylesheets. This * method determines the proper import precedence of all imported * stylesheets. It then iterates through all of the elements and * properties in the proper order and triggers the individual recompose * methods. * * @throws TransformerException */ public void recompose() throws TransformerException { // Now we make a Vector that is going to hold all of the recomposable elements Vector recomposableElements = new Vector(); // First, we build the global import tree. if (null == m_globalImportList) { Vector importList = new Vector(); addImports(this, true, importList); // Now we create an array and reverse the order of the importList vector. // We built the importList vector backwards so that we could use addElement // to append to the end of the vector instead of constantly pushing new // stylesheets onto the front of the vector and having to shift the rest // of the vector each time. m_globalImportList = new StylesheetComposed[importList.size()]; for (int i = 0, j= importList.size() -1; i < importList.size(); i++) { m_globalImportList[j] = (StylesheetComposed) importList.elementAt(i); // Build the global include list for this stylesheet. // This needs to be done ahead of the recomposeImports // because we need the info from the composed includes. m_globalImportList[j].recomposeIncludes(m_globalImportList[j]); // Calculate the number of this import. m_globalImportList[j--].recomposeImports(); } } // Next, we walk the import tree and add all of the recomposable elements to the vector. int n = getGlobalImportCount(); for (int i = 0; i < n; i++) { StylesheetComposed imported = getGlobalImport(i); imported.recompose(recomposableElements); } // We sort the elements into ascending order. QuickSort2(recomposableElements, 0, recomposableElements.size() - 1); // We set up the global variables that will hold the recomposed information. m_outputProperties = new OutputProperties(org.apache.xml.serializer.Method.UNKNOWN); // m_outputProperties = new OutputProperties(Method.XML); m_attrSets = new HashMap(); m_decimalFormatSymbols = new Hashtable(); m_keyDecls = new Vector(); m_namespaceAliasComposed = new Hashtable(); m_templateList = new TemplateList(); m_variables = new Vector(); // Now we sequence through the sorted elements, // calling the recompose() function on each one. This will call back into the // appropriate routine here to actually do the recomposition. // Note that we're going backwards, encountering the highest precedence items first. for (int i = recomposableElements.size() - 1; i >= 0; i--) ((ElemTemplateElement) recomposableElements.elementAt(i)).recompose(this); /* * Backing out REE again, as it seems to cause some new failures * which need to be investigated. -is */ // This has to be done before the initialization of the compose state, because // eleminateRedundentGlobals will add variables to the m_variables vector, which // it then copied in the ComposeState constructor. // if(true && org.apache.xalan.processor.TransformerFactoryImpl.m_optimize) // { // RedundentExprEliminator ree = new RedundentExprEliminator(); // callVisitors(ree); // ree.eleminateRedundentGlobals(this); // } initComposeState(); // Need final composition of TemplateList. This adds the wild cards onto the chains. m_templateList.compose(this); // Need to clear check for properties at the same import level. m_outputProperties.compose(this); m_outputProperties.endCompose(this); // Now call the compose() method on every element to give it a chance to adjust // based on composed values. n = getGlobalImportCount(); for (int i = 0; i < n; i++) { StylesheetComposed imported = this.getGlobalImport(i); int includedCount = imported.getIncludeCountComposed(); for (int j = -1; j < includedCount; j++) { Stylesheet included = imported.getIncludeComposed(j); composeTemplates(included); } } // Attempt to register any remaining unregistered extension namespaces. if (m_extNsMgr != null) m_extNsMgr.registerUnregisteredNamespaces(); clearComposeState(); } /** * Call the compose function for each ElemTemplateElement. * * @param templ non-null reference to template element that will have * the composed method called on it, and will have it's children's composed * methods called. */ void composeTemplates(ElemTemplateElement templ) throws TransformerException { templ.compose(this); for (ElemTemplateElement child = templ.getFirstChildElem(); child != null; child = child.getNextSiblingElem()) { composeTemplates(child); } templ.endCompose(this); } /** * The combined list of imports. The stylesheet with the highest * import precedence will be at element 0. The one with the lowest * import precedence will be at element length - 1. * @serial */ private StylesheetComposed[] m_globalImportList; /** * Add the imports in the given sheet to the working importList vector. * The will be added from highest import precedence to * least import precedence. This is a post-order traversal of the * import tree as described in the * XSLT Recommendation. *

For example, suppose

*

stylesheet A imports stylesheets B and C in that order;

*

stylesheet B imports stylesheet D;

*

stylesheet C imports stylesheet E.

*

Then the order of import precedence (highest first) is * A, C, E, B, D.

* * @param stylesheet Stylesheet to examine for imports. * @param addToList true if this template should be added to the import list * @param importList The working import list. Templates are added here in the reverse * order of priority. When we're all done, we'll reverse this to the correct * priority in an array. */ protected void addImports(Stylesheet stylesheet, boolean addToList, Vector importList) { // Get the direct imports of this sheet. int n = stylesheet.getImportCount(); if (n > 0) { for (int i = 0; i < n; i++) { Stylesheet imported = stylesheet.getImport(i); addImports(imported, true, importList); } } n = stylesheet.getIncludeCount(); if (n > 0) { for (int i = 0; i < n; i++) { Stylesheet included = stylesheet.getInclude(i); addImports(included, false, importList); } } if (addToList) importList.addElement(stylesheet); } /** * Get a stylesheet from the global import list. * TODO: JKESS PROPOSES SPECIAL-CASE FOR NO IMPORT LIST, TO MATCH COUNT. * * @param i Index of stylesheet to get from global import list * * @return The stylesheet at the given index */ public StylesheetComposed getGlobalImport(int i) { return m_globalImportList[i]; } /** * Get the total number of imports in the global import list. * * @return The total number of imported stylesheets, including * the root stylesheet, thus the number will always be 1 or * greater. * TODO: JKESS PROPOSES SPECIAL-CASE FOR NO IMPORT LIST, TO MATCH DESCRIPTION. */ public int getGlobalImportCount() { return (m_globalImportList!=null) ? m_globalImportList.length : 1; } /** * Given a stylesheet, return the number of the stylesheet * in the global import list. * @param sheet The stylesheet which will be located in the * global import list. * @return The index into the global import list of the given stylesheet, * or -1 if it is not found (which should never happen). */ public int getImportNumber(StylesheetComposed sheet) { if (this == sheet) return 0; int n = getGlobalImportCount(); for (int i = 0; i < n; i++) { if (sheet == getGlobalImport(i)) return i; } return -1; } /** * This will be set up with the default values, and then the values * will be set as stylesheets are encountered. * @serial */ private OutputProperties m_outputProperties; /** * Recompose the output format object from the included elements. * * @param oprops non-null reference to xsl:output properties representation. */ void recomposeOutput(OutputProperties oprops) throws TransformerException { m_outputProperties.copyFrom(oprops); } /** * Get the combined "xsl:output" property with the properties * combined from the included stylesheets. If a xsl:output * is not declared in this stylesheet or an included stylesheet, * look in the imports. * Please note that this returns a reference to the OutputProperties * object, not a cloned object, like getOutputProperties does. * @see output in XSLT Specification * * @return non-null reference to composed output properties object. */ public OutputProperties getOutputComposed() { // System.out.println("getOutputComposed.getIndent: "+m_outputProperties.getIndent()); // System.out.println("getOutputComposed.getIndenting: "+m_outputProperties.getIndenting()); return m_outputProperties; } /** Flag indicating whether an output method has been set by the user. * @serial */ private boolean m_outputMethodSet = false; /** * Find out if an output method has been set by the user. * * @return Value indicating whether an output method has been set by the user * @xsl.usage internal */ public boolean isOutputMethodSet() { return m_outputMethodSet; } /** * Composed set of all included and imported attribute set properties. * Each entry is a vector of ElemAttributeSet objects. * @serial */ private HashMap m_attrSets; /** * Recompose the attribute-set declarations. * * @param attrSet An attribute-set to add to the hashtable of attribute sets. */ void recomposeAttributeSets(ElemAttributeSet attrSet) { ArrayList attrSetList = (ArrayList) m_attrSets.get(attrSet.getName()); if (null == attrSetList) { attrSetList = new ArrayList(); m_attrSets.put(attrSet.getName(), attrSetList); } attrSetList.add(attrSet); } /** * Get a list "xsl:attribute-set" properties that match the qname. * @see attribute-sets in XSLT Specification * * @param name Qualified name of attribute set properties to get * * @return A vector of attribute sets matching the given name * * @throws ArrayIndexOutOfBoundsException */ public ArrayList getAttributeSetComposed(QName name) throws ArrayIndexOutOfBoundsException { return (ArrayList) m_attrSets.get(name); } /** * Table of DecimalFormatSymbols, keyed by QName. * @serial */ private Hashtable m_decimalFormatSymbols; /** * Recompose the decimal-format declarations. * * @param dfp A DecimalFormatProperties to add to the hashtable of decimal formats. */ void recomposeDecimalFormats(DecimalFormatProperties dfp) { DecimalFormatSymbols oldDfs = (DecimalFormatSymbols) m_decimalFormatSymbols.get(dfp.getName()); if (null == oldDfs) { m_decimalFormatSymbols.put(dfp.getName(), dfp.getDecimalFormatSymbols()); } else if (!dfp.getDecimalFormatSymbols().equals(oldDfs)) { String themsg; if (dfp.getName().equals(new QName(""))) { // "Only one default xsl:decimal-format declaration is allowed." themsg = XSLMessages.createWarning( XSLTErrorResources.WG_ONE_DEFAULT_XSLDECIMALFORMAT_ALLOWED, new Object[0]); } else { // "xsl:decimal-format names must be unique. Name {0} has been duplicated." themsg = XSLMessages.createWarning( XSLTErrorResources.WG_XSLDECIMALFORMAT_NAMES_MUST_BE_UNIQUE, new Object[] {dfp.getName()}); } error(themsg); // Should we throw TransformerException instead? } } /** * Given a valid element decimal-format name, return the * decimalFormatSymbols with that name. *

It is an error to declare either the default decimal-format or * a decimal-format with a given name more than once (even with * different import precedence), unless it is declared every * time with the same value for all attributes (taking into * account any default values).

*

Which means, as far as I can tell, the decimal-format * properties are not additive.

* * @param name Qualified name of the decimal format to find * @return DecimalFormatSymbols object matching the given name or * null if name is not found. */ public DecimalFormatSymbols getDecimalFormatComposed(QName name) { return (DecimalFormatSymbols) m_decimalFormatSymbols.get(name); } /** * A list of all key declarations visible from this stylesheet and all * lesser stylesheets. * @serial */ private Vector m_keyDecls; /** * Recompose the key declarations. * * @param keyDecl A KeyDeclaration to be added to the vector of key declarations. */ void recomposeKeys(KeyDeclaration keyDecl) { m_keyDecls.addElement(keyDecl); } /** * Get the composed "xsl:key" properties. * @see key in XSLT Specification * * @return A vector of the composed "xsl:key" properties. */ public Vector getKeysComposed() { return m_keyDecls; } /** * Composed set of all namespace aliases. * @serial */ private Hashtable m_namespaceAliasComposed; /** * Recompose the namespace-alias declarations. * * @param nsAlias A NamespaceAlias object to add to the hashtable of namespace aliases. */ void recomposeNamespaceAliases(NamespaceAlias nsAlias) { m_namespaceAliasComposed.put(nsAlias.getStylesheetNamespace(), nsAlias); } /** * Get the "xsl:namespace-alias" property. * Return the NamespaceAlias for a given namespace uri. * @see literal-result-element in XSLT Specification * * @param uri non-null reference to namespace that is to be aliased. * * @return NamespaceAlias that matches uri, or null if no match. */ public NamespaceAlias getNamespaceAliasComposed(String uri) { return (NamespaceAlias) ((null == m_namespaceAliasComposed) ? null : m_namespaceAliasComposed.get(uri)); } /** * The "xsl:template" properties. * @serial */ private TemplateList m_templateList; /** * Recompose the template declarations. * * @param template An ElemTemplate object to add to the template list. */ void recomposeTemplates(ElemTemplate template) { m_templateList.setTemplate(template); } /** * Accessor method to retrieve the TemplateList associated with * this StylesheetRoot. * * @return The composed TemplateList. */ public final TemplateList getTemplateListComposed() { return m_templateList; } /** * Mutator method to set the TemplateList associated with this * StylesheetRoot. This method should only be used by the compiler. Normally, * the template list is built during the recompose process and should not be * altered by the user. * @param templateList The new TemplateList for this StylesheetRoot. */ public final void setTemplateListComposed(TemplateList templateList) { m_templateList = templateList; } /** * Get an "xsl:template" property by node match. This looks in the imports as * well as this stylesheet. * @see section-Defining-Template-Rules in XSLT Specification * * @param xctxt non-null reference to XPath runtime execution context. * @param targetNode non-null reference of node that the template must match. * @param mode qualified name of the node, or null. * @param quietConflictWarnings true if conflict warnings should not be reported. * * @return reference to ElemTemplate that is the best match for targetNode, or * null if no match could be made. * * @throws TransformerException */ public ElemTemplate getTemplateComposed(XPathContext xctxt, int targetNode, QName mode, boolean quietConflictWarnings, DTM dtm) throws TransformerException { return m_templateList.getTemplate(xctxt, targetNode, mode, quietConflictWarnings, dtm); } /** * Get an "xsl:template" property by node match. This looks in the imports as * well as this stylesheet. * @see section-Defining-Template-Rules in XSLT Specification * * @param xctxt non-null reference to XPath runtime execution context. * @param targetNode non-null reference of node that the template must match. * @param mode qualified name of the node, or null. * @param maxImportLevel The maximum importCountComposed that we should consider or -1 * if we should consider all import levels. This is used by apply-imports to * access templates that have been overridden. * @param endImportLevel The count of composed imports * @param quietConflictWarnings true if conflict warnings should not be reported. * * @return reference to ElemTemplate that is the best match for targetNode, or * null if no match could be made. * * @throws TransformerException */ public ElemTemplate getTemplateComposed(XPathContext xctxt, int targetNode, QName mode, int maxImportLevel, int endImportLevel, boolean quietConflictWarnings, DTM dtm) throws TransformerException { return m_templateList.getTemplate(xctxt, targetNode, mode, maxImportLevel, endImportLevel, quietConflictWarnings, dtm); } /** * Get an "xsl:template" property. This looks in the imports as * well as this stylesheet. * @see section-Defining-Template-Rules in XSLT Specification * * @param qname non-null reference to qualified name of template. * * @return reference to named template, or null if not found. */ public ElemTemplate getTemplateComposed(QName qname) { return m_templateList.getTemplate(qname); } /** * Composed set of all variables and params. * @serial */ private Vector m_variables; /** * Recompose the top level variable and parameter declarations. * * @param elemVar A top level variable or parameter to be added to the Vector. */ void recomposeVariables(ElemVariable elemVar) { // Don't overide higher priority variable if (getVariableOrParamComposed(elemVar.getName()) == null) { elemVar.setIsTopLevel(true); // Mark as a top-level variable or param elemVar.setIndex(m_variables.size()); m_variables.addElement(elemVar); } } /** * Get an "xsl:variable" property. * @see top-level-variables in XSLT Specification * * @param qname Qualified name of variable or param * * @return The ElemVariable with the given qualified name */ public ElemVariable getVariableOrParamComposed(QName qname) { if (null != m_variables) { int n = m_variables.size(); for (int i = 0; i < n; i++) { ElemVariable var = (ElemVariable)m_variables.elementAt(i); if(var.getName().equals(qname)) return var; } } return null; } /** * Get all global "xsl:variable" properties in scope for this stylesheet. * @see top-level-variables in XSLT Specification * * @return Vector of all variables and params in scope */ public Vector getVariablesAndParamsComposed() { return m_variables; } /** * A list of properties that specify how to do space * stripping. This uses the same exact mechanism as Templates. * @serial */ private TemplateList m_whiteSpaceInfoList; /** * Recompose the strip-space and preserve-space declarations. * * @param wsi A WhiteSpaceInfo element to add to the list of WhiteSpaceInfo elements. */ void recomposeWhiteSpaceInfo(WhiteSpaceInfo wsi) { if (null == m_whiteSpaceInfoList) m_whiteSpaceInfoList = new TemplateList(); m_whiteSpaceInfoList.setTemplate(wsi); } /** * Check to see if the caller should bother with check for * whitespace nodes. * * @return Whether the caller should bother with check for * whitespace nodes. */ public boolean shouldCheckWhitespace() { return null != m_whiteSpaceInfoList; } /** * Get information about whether or not an element should strip whitespace. * @see strip in XSLT Specification * * @param support The XPath runtime state. * @param targetElement Element to check * * @return WhiteSpaceInfo for the given element * * @throws TransformerException */ public WhiteSpaceInfo getWhiteSpaceInfo( XPathContext support, int targetElement, DTM dtm) throws TransformerException { if (null != m_whiteSpaceInfoList) return (WhiteSpaceInfo) m_whiteSpaceInfoList.getTemplate(support, targetElement, null, false, dtm); else return null; } /** * Get information about whether or not an element should strip whitespace. * @see strip in XSLT Specification * * @param support The XPath runtime state. * @param targetElement Element to check * * @return true if the whitespace should be stripped. * * @throws TransformerException */ public boolean shouldStripWhiteSpace( XPathContext support, int targetElement) throws TransformerException { if (null != m_whiteSpaceInfoList) { while(DTM.NULL != targetElement) { DTM dtm = support.getDTM(targetElement); WhiteSpaceInfo info = (WhiteSpaceInfo) m_whiteSpaceInfoList.getTemplate(support, targetElement, null, false, dtm); if(null != info) return info.getShouldStripSpace(); int parent = dtm.getParent(targetElement); if(DTM.NULL != parent && DTM.ELEMENT_NODE == dtm.getNodeType(parent)) targetElement = parent; else targetElement = DTM.NULL; } } return false; } /** * Get information about whether or not whitespace can be stripped. * @see strip in XSLT Specification * * @return true if the whitespace can be stripped. */ public boolean canStripWhiteSpace() { return (null != m_whiteSpaceInfoList); } /** * The default template to use for text nodes if we don't find * anything else. This is initialized in initDefaultRule(). * @serial * @xsl.usage advanced */ private ElemTemplate m_defaultTextRule; /** * Get the default template for text. * * @return the default template for text. * @xsl.usage advanced */ public final ElemTemplate getDefaultTextRule() { return m_defaultTextRule; } /** * The default template to use if we don't find anything * else. This is initialized in initDefaultRule(). * @serial * @xsl.usage advanced */ private ElemTemplate m_defaultRule; /** * Get the default template for elements. * * @return the default template for elements. * @xsl.usage advanced */ public final ElemTemplate getDefaultRule() { return m_defaultRule; } /** * The default template to use for the root if we don't find * anything else. This is initialized in initDefaultRule(). * We kind of need this because the defaultRule isn't good * enough because it doesn't supply a document context. * For now, I default the root document element to "HTML". * Don't know if this is really a good idea or not. * I suspect it is not. * @serial * @xsl.usage advanced */ private ElemTemplate m_defaultRootRule; /** * Get the default template for a root node. * * @return The default template for a root node. * @xsl.usage advanced */ public final ElemTemplate getDefaultRootRule() { return m_defaultRootRule; } /** * The start rule to kick off the transformation. * @serial * @xsl.usage advanced */ private ElemTemplate m_startRule; /** * Get the default template for a root node. * * @return The default template for a root node. * @xsl.usage advanced */ public final ElemTemplate getStartRule() { return m_startRule; } /** * Used for default selection. * @serial */ XPath m_selectDefault; /** * Create the default rule if needed. * * @throws TransformerException */ private void initDefaultRule(ErrorListener errorListener) throws TransformerException { // Then manufacture a default m_defaultRule = new ElemTemplate(); m_defaultRule.setStylesheet(this); XPath defMatch = new XPath("*", this, this, XPath.MATCH, errorListener); m_defaultRule.setMatch(defMatch); ElemApplyTemplates childrenElement = new ElemApplyTemplates(); childrenElement.setIsDefaultTemplate(true); childrenElement.setSelect(m_selectDefault); m_defaultRule.appendChild(childrenElement); m_startRule = m_defaultRule; // ----------------------------- m_defaultTextRule = new ElemTemplate(); m_defaultTextRule.setStylesheet(this); defMatch = new XPath("text() | @*", this, this, XPath.MATCH, errorListener); m_defaultTextRule.setMatch(defMatch); ElemValueOf elemValueOf = new ElemValueOf(); m_defaultTextRule.appendChild(elemValueOf); XPath selectPattern = new XPath(".", this, this, XPath.SELECT, errorListener); elemValueOf.setSelect(selectPattern); //-------------------------------- m_defaultRootRule = new ElemTemplate(); m_defaultRootRule.setStylesheet(this); defMatch = new XPath("/", this, this, XPath.MATCH, errorListener); m_defaultRootRule.setMatch(defMatch); childrenElement = new ElemApplyTemplates(); childrenElement.setIsDefaultTemplate(true); m_defaultRootRule.appendChild(childrenElement); childrenElement.setSelect(m_selectDefault); } /** * This is a generic version of C.A.R Hoare's Quick Sort * algorithm. This will handle arrays that are already * sorted, and arrays with duplicate keys. It was lifted from * the NodeSorter class but should probably be eliminated and replaced * with a call to Collections.sort when we migrate to Java2.
* * If you think of a one dimensional array as going from * the lowest index on the left to the highest index on the right * then the parameters to this function are lowest index or * left and highest index or right. The first time you call * this function it will be with the parameters 0, a.length - 1. * * @param v a vector of ElemTemplateElement elements * @param lo0 left boundary of partition * @param hi0 right boundary of partition * */ private void QuickSort2(Vector v, int lo0, int hi0) { int lo = lo0; int hi = hi0; if ( hi0 > lo0) { // Arbitrarily establishing partition element as the midpoint of // the array. ElemTemplateElement midNode = (ElemTemplateElement) v.elementAt( ( lo0 + hi0 ) / 2 ); // loop through the array until indices cross while( lo <= hi ) { // find the first element that is greater than or equal to // the partition element starting from the left Index. while( (lo < hi0) && (((ElemTemplateElement) v.elementAt(lo)).compareTo(midNode) < 0) ) { ++lo; } // end while // find an element that is smaller than or equal to // the partition element starting from the right Index. while( (hi > lo0) && (((ElemTemplateElement) v.elementAt(hi)).compareTo(midNode) > 0) ) { --hi; } // if the indexes have not crossed, swap if( lo <= hi ) { ElemTemplateElement node = (ElemTemplateElement) v.elementAt(lo); v.setElementAt(v.elementAt(hi), lo); v.setElementAt(node, hi); ++lo; --hi; } } // If the right index has not reached the left side of array // must now sort the left partition. if( lo0 < hi ) { QuickSort2( v, lo0, hi ); } // If the left index has not reached the right side of array // must now sort the right partition. if( lo < hi0 ) { QuickSort2( v, lo, hi0 ); } } } // end QuickSort2 */ private transient ComposeState m_composeState; /** * Initialize a new ComposeState. */ void initComposeState() { m_composeState = new ComposeState(); } /** * Return class to track state global state during the compose() operation. * @return ComposeState reference, or null if endCompose has been called. */ ComposeState getComposeState() { return m_composeState; } /** * Clear the compose state. */ private void clearComposeState() { m_composeState = null; } private String m_extensionHandlerClass = "org.apache.xalan.extensions.ExtensionHandlerExsltFunction"; /** * This internal method allows the setting of the java class * to handle the extension function (if other than the default one). * * @xsl.usage internal */ public String setExtensionHandlerClass(String handlerClassName) { String oldvalue = m_extensionHandlerClass; m_extensionHandlerClass = handlerClassName; return oldvalue; } /** * * @xsl.usage internal */ public String getExtensionHandlerClass() { return m_extensionHandlerClass; } /** * Class to track state global state during the compose() operation. */ class ComposeState { ComposeState() { int size = m_variables.size(); for (int i = 0; i < size; i++) { ElemVariable ev = (ElemVariable)m_variables.elementAt(i); m_variableNames.addElement(ev.getName()); } } private ExpandedNameTable m_ent = new ExpandedNameTable(); /** * Given a qualified name, return an integer ID that can be * quickly compared. * * @param qname a qualified name object, must not be null. * * @return the expanded-name id of the qualified name. */ public int getQNameID(QName qname) { return m_ent.getExpandedTypeID(qname.getNamespace(), qname.getLocalName(), // The type doesn't matter for our // purposes. org.apache.xml.dtm.DTM.ELEMENT_NODE); } /** * A Vector of the current params and QNames within the current template. * Set by ElemTemplate and used by ProcessorVariable. */ private java.util.Vector m_variableNames = new java.util.Vector(); /** * Add the name of a qualified name within the template. The position in * the vector is its ID. * @param qname A qualified name of a param or variable, should be non-null. * @return the index where the variable was added. */ int addVariableName(final org.apache.xml.utils.QName qname) { int pos = m_variableNames.size(); m_variableNames.addElement(qname); int frameSize = m_variableNames.size() - getGlobalsSize(); if(frameSize > m_maxStackFrameSize) m_maxStackFrameSize++; return pos; } void resetStackFrameSize() { m_maxStackFrameSize = 0; } int getFrameSize() { return m_maxStackFrameSize; } /** * Get the current size of the stack frame. Use this to record the position * in a template element at startElement, so that it can be popped * at endElement. */ int getCurrentStackFrameSize() { return m_variableNames.size(); } /** * Set the current size of the stack frame. */ void setCurrentStackFrameSize(int sz) { m_variableNames.setSize(sz); } int getGlobalsSize() { return m_variables.size(); } IntStack m_marks = new IntStack(); void pushStackMark() { m_marks.push(getCurrentStackFrameSize()); } void popStackMark() { int mark = m_marks.pop(); setCurrentStackFrameSize(mark); } /** * Get the Vector of the current params and QNames to be collected * within the current template. * @return A reference to the vector of variable names. The reference * returned is owned by this class, and so should not really be mutated, or * stored anywhere. */ java.util.Vector getVariableNames() { return m_variableNames; } private int m_maxStackFrameSize; } /** * @return Optimization flag */ public boolean getOptimizer() { return m_optimizer; } /** * @param b Optimization flag */ public void setOptimizer(boolean b) { m_optimizer = b; } /** * @return Incremental flag */ public boolean getIncremental() { return m_incremental; } /** * @return source location flag */ public boolean getSource_location() { return m_source_location; } /** * @param b Incremental flag */ public void setIncremental(boolean b) { m_incremental = b; } /** * @param b Source location flag */ public void setSource_location(boolean b) { m_source_location = b; } }