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