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