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