1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the  "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 /*
19  * $Id: StylesheetHandler.java 468640 2006-10-28 06:53:53Z minchau $
20  */
21 package org.apache.xalan.processor;
22 
23 import java.util.Stack;
24 
25 import javax.xml.transform.ErrorListener;
26 import javax.xml.transform.Source;
27 import javax.xml.transform.SourceLocator;
28 import javax.xml.transform.Templates;
29 import javax.xml.transform.TransformerConfigurationException;
30 import javax.xml.transform.TransformerException;
31 import javax.xml.transform.sax.TemplatesHandler;
32 
33 import org.apache.xalan.extensions.ExpressionVisitor;
34 import org.apache.xalan.res.XSLMessages;
35 import org.apache.xalan.res.XSLTErrorResources;
36 import org.apache.xalan.templates.Constants;
37 import org.apache.xalan.templates.ElemForEach;
38 import org.apache.xalan.templates.ElemTemplateElement;
39 import org.apache.xalan.templates.Stylesheet;
40 import org.apache.xalan.templates.StylesheetRoot;
41 import org.apache.xml.utils.BoolStack;
42 import org.apache.xml.utils.NamespaceSupport2;
43 import org.apache.xml.utils.NodeConsumer;
44 import org.apache.xml.utils.PrefixResolver;
45 import org.apache.xml.utils.SAXSourceLocator;
46 import org.apache.xml.utils.XMLCharacterRecognizer;
47 import org.apache.xpath.XPath;
48 import org.apache.xpath.compiler.FunctionTable;
49 import org.apache.xpath.functions.Function;
50 
51 import org.w3c.dom.Node;
52 
53 import org.xml.sax.Attributes;
54 import org.xml.sax.InputSource;
55 import org.xml.sax.Locator;
56 import org.xml.sax.helpers.DefaultHandler;
57 import org.xml.sax.helpers.NamespaceSupport;
58 
59 /**
60  * Initializes and processes a stylesheet via SAX events.
61  * This class acts as essentially a state machine, maintaining
62  * a ContentHandler stack, and pushing appropriate content
63  * handlers as parse events occur.
64  * @xsl.usage advanced
65  */
66 public class StylesheetHandler extends DefaultHandler
67         implements TemplatesHandler, PrefixResolver, NodeConsumer
68 {
69 
70 
71   /**
72    * The function table of XPath and XSLT;
73    */
74   private FunctionTable m_funcTable = new FunctionTable();
75 
76   /**
77    * The flag for the setting of the optimize feature;
78    */
79   private boolean m_optimize = true;
80 
81   /**
82    * The flag for the setting of the incremental feature;
83    */
84   private boolean m_incremental = false;
85 
86   /**
87    * The flag for the setting of the source_location feature;
88    */
89   private boolean m_source_location = false;
90 
91   /**
92    * Create a StylesheetHandler object, creating a root stylesheet
93    * as the target.
94    *
95    * @param processor non-null reference to the transformer factory that owns this handler.
96    *
97    * @throws TransformerConfigurationException if a StylesheetRoot
98    * can not be constructed for some reason.
99    */
StylesheetHandler(TransformerFactoryImpl processor)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    */
init(TransformerFactoryImpl processor)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    */
createXPath(String str, ElemTemplateElement owningTemplate)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    */
createMatchPatternXPath(String str, ElemTemplateElement owningTemplate)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    */
getNamespaceForPrefix(String prefix)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    */
getNamespaceForPrefix(String prefix, org.w3c.dom.Node context)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    */
stackContains(Stack stack, String url)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    */
getTemplates()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    */
setSystemId(String baseID)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    */
getSystemId()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    */
resolveEntity(String publicId, String systemId)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    */
notationDecl(String name, String publicId, String systemId)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    */
unparsedEntityDecl(String name, String publicId, String systemId, String notationName)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    */
getProcessorFor( String uri, String localName, String rawName)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    */
setDocumentLocator(Locator locator)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    */
startDocument()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    */
isStylesheetParsingComplete()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    */
endDocument()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    */
startPrefixMapping(String prefix, String uri)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    */
endPrefixMapping(String prefix)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    */
flushCharacters()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    */
startElement( String uri, String localName, String rawName, Attributes attributes)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    */
endElement(String uri, String localName, String rawName)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    */
characters(char ch[], int start, int length)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    */
ignorableWhitespace(char ch[], int start, int length)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    */
processingInstruction(String target, String data)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    */
skippedEntity(String name)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    */
warn(String msg, Object args[])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    */
assertion(boolean condition, String msg)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    */
error(String msg, Exception e)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    */
error(String msg, Object args[], Exception e)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    */
warning(org.xml.sax.SAXParseException e)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    */
error(org.xml.sax.SAXParseException e)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    */
fatalError(org.xml.sax.SAXParseException e)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    */
checkForFragmentID(Attributes attributes)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    */
getStylesheetProcessor()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    */
getStylesheetType()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    */
setStylesheetType(int type)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    */
getStylesheet()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    */
getLastPoppedStylesheet()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    */
getStylesheetRoot()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    */
pushStylesheet(Stylesheet s)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    */
popStylesheet()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    */
getCurrentProcessor()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    */
pushProcessor(XSLTElementProcessor processor)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    */
popProcessor()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    */
getSchema()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    */
getElemTemplateElement()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    */
nextUid()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    */
pushElemTemplateElement(ElemTemplateElement elem)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    */
popElemTemplateElement()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    */
pushBaseIndentifier(String baseID)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    */
popBaseIndentifier()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    */
getBaseIdentifier()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    */
getLocator()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    */
pushImportURL(String hrefUrl)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    */
pushImportSource(Source sourceFromURIResolver)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    */
importStackContains(String hrefUrl)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    */
popImportURL()1514   String popImportURL()
1515   {
1516     return (String) m_importStack.pop();
1517   }
1518 
peekImportURL()1519   String peekImportURL()
1520   {
1521     return (String) m_importStack.peek();
1522   }
1523 
peekSourceFromURIResolver()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    */
popImportSource()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    */
pushNewNamespaceSupport()1550   void pushNewNamespaceSupport()
1551   {
1552     m_nsSupportStack.push(new NamespaceSupport2());
1553   }
1554 
1555   /**
1556    * Pop the current NamespaceSupport object.
1557    *
1558    */
popNamespaceSupport()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    */
getNamespaceSupport()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    */
setOriginatingNode(Node n)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    */
getOriginatingNode()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    */
isSpacePreserve()1616   boolean isSpacePreserve()
1617   {
1618     return m_spacePreserveStack.peek();
1619   }
1620 
1621   /**
1622    * Pop boolean value from the spacePreserve stack.
1623    */
popSpaceHandling()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    */
pushSpaceHandling(boolean b)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    */
pushSpaceHandling(Attributes attrs)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 
getElemVersion()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      */
handlesNullPrefixes()1699     public boolean handlesNullPrefixes() {
1700         return false;
1701     }
1702 
1703     /**
1704      * @return Optimization flag
1705      */
getOptimize()1706     public boolean getOptimize() {
1707         return m_optimize;
1708     }
1709 
1710     /**
1711      * @return Incremental flag
1712      */
getIncremental()1713     public boolean getIncremental() {
1714         return m_incremental;
1715     }
1716 
1717     /**
1718      * @return Source Location flag
1719      */
getSource_location()1720     public boolean getSource_location() {
1721         return m_source_location;
1722     }
1723 
1724 }
1725 
1726 
1727 
1728