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