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 */
21package org.apache.xalan.processor;
22
23import java.util.Stack;
24
25import javax.xml.transform.ErrorListener;
26import javax.xml.transform.Source;
27import javax.xml.transform.SourceLocator;
28import javax.xml.transform.Templates;
29import javax.xml.transform.TransformerConfigurationException;
30import javax.xml.transform.TransformerException;
31import javax.xml.transform.sax.TemplatesHandler;
32
33import org.apache.xalan.extensions.ExpressionVisitor;
34import org.apache.xalan.res.XSLMessages;
35import org.apache.xalan.res.XSLTErrorResources;
36import org.apache.xalan.templates.Constants;
37import org.apache.xalan.templates.ElemForEach;
38import org.apache.xalan.templates.ElemTemplateElement;
39import org.apache.xalan.templates.Stylesheet;
40import org.apache.xalan.templates.StylesheetRoot;
41import org.apache.xml.utils.BoolStack;
42import org.apache.xml.utils.NamespaceSupport2;
43import org.apache.xml.utils.NodeConsumer;
44import org.apache.xml.utils.PrefixResolver;
45import org.apache.xml.utils.SAXSourceLocator;
46import org.apache.xml.utils.XMLCharacterRecognizer;
47import org.apache.xpath.XPath;
48import org.apache.xpath.compiler.FunctionTable;
49import org.apache.xpath.functions.Function;
50
51import org.w3c.dom.Node;
52
53import org.xml.sax.Attributes;
54import org.xml.sax.InputSource;
55import org.xml.sax.Locator;
56import org.xml.sax.helpers.DefaultHandler;
57import 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 */
66public 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@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