| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| /* |
| * $Id: StylesheetHandler.java 468640 2006-10-28 06:53:53Z minchau $ |
| */ |
| package org.apache.xalan.processor; |
| |
| import java.util.Stack; |
| |
| import javax.xml.transform.ErrorListener; |
| import javax.xml.transform.Source; |
| import javax.xml.transform.SourceLocator; |
| import javax.xml.transform.Templates; |
| import javax.xml.transform.TransformerConfigurationException; |
| import javax.xml.transform.TransformerException; |
| import javax.xml.transform.sax.TemplatesHandler; |
| |
| import org.apache.xalan.extensions.ExpressionVisitor; |
| import org.apache.xalan.res.XSLMessages; |
| import org.apache.xalan.res.XSLTErrorResources; |
| import org.apache.xalan.templates.Constants; |
| import org.apache.xalan.templates.ElemForEach; |
| import org.apache.xalan.templates.ElemTemplateElement; |
| import org.apache.xalan.templates.Stylesheet; |
| import org.apache.xalan.templates.StylesheetRoot; |
| import org.apache.xml.utils.BoolStack; |
| import org.apache.xml.utils.NamespaceSupport2; |
| import org.apache.xml.utils.NodeConsumer; |
| import org.apache.xml.utils.PrefixResolver; |
| import org.apache.xml.utils.SAXSourceLocator; |
| import org.apache.xml.utils.XMLCharacterRecognizer; |
| import org.apache.xpath.XPath; |
| import org.apache.xpath.compiler.FunctionTable; |
| import org.apache.xpath.functions.Function; |
| |
| import org.w3c.dom.Node; |
| |
| import org.xml.sax.Attributes; |
| import org.xml.sax.InputSource; |
| import org.xml.sax.Locator; |
| import org.xml.sax.helpers.DefaultHandler; |
| import org.xml.sax.helpers.NamespaceSupport; |
| |
| /** |
| * Initializes and processes a stylesheet via SAX events. |
| * This class acts as essentially a state machine, maintaining |
| * a ContentHandler stack, and pushing appropriate content |
| * handlers as parse events occur. |
| * @xsl.usage advanced |
| */ |
| public class StylesheetHandler extends DefaultHandler |
| implements TemplatesHandler, PrefixResolver, NodeConsumer |
| { |
| |
| |
| /** |
| * The function table of XPath and XSLT; |
| */ |
| private FunctionTable m_funcTable = new FunctionTable(); |
| |
| /** |
| * The flag for the setting of the optimize feature; |
| */ |
| private boolean m_optimize = true; |
| |
| /** |
| * The flag for the setting of the incremental feature; |
| */ |
| private boolean m_incremental = false; |
| |
| /** |
| * The flag for the setting of the source_location feature; |
| */ |
| private boolean m_source_location = false; |
| |
| /** |
| * Create a StylesheetHandler object, creating a root stylesheet |
| * as the target. |
| * |
| * @param processor non-null reference to the transformer factory that owns this handler. |
| * |
| * @throws TransformerConfigurationException if a StylesheetRoot |
| * can not be constructed for some reason. |
| */ |
| public StylesheetHandler(TransformerFactoryImpl processor) |
| throws TransformerConfigurationException |
| { |
| Class func = org.apache.xalan.templates.FuncDocument.class; |
| m_funcTable.installFunction("document", func); |
| |
| // func = new org.apache.xalan.templates.FuncKey(); |
| // FunctionTable.installFunction("key", func); |
| func = org.apache.xalan.templates.FuncFormatNumb.class; |
| |
| m_funcTable.installFunction("format-number", func); |
| |
| m_optimize =((Boolean) processor.getAttribute( |
| TransformerFactoryImpl.FEATURE_OPTIMIZE)).booleanValue(); |
| m_incremental = ((Boolean) processor.getAttribute( |
| TransformerFactoryImpl.FEATURE_INCREMENTAL)).booleanValue(); |
| m_source_location = ((Boolean) processor.getAttribute( |
| TransformerFactoryImpl.FEATURE_SOURCE_LOCATION)).booleanValue(); |
| // m_schema = new XSLTSchema(); |
| init(processor); |
| |
| } |
| |
| /** |
| * Do common initialization. |
| * |
| * @param processor non-null reference to the transformer factory that owns this handler. |
| */ |
| void init(TransformerFactoryImpl processor) |
| { |
| m_stylesheetProcessor = processor; |
| |
| // Set the initial content handler. |
| m_processors.push(m_schema.getElementProcessor()); |
| this.pushNewNamespaceSupport(); |
| |
| // m_includeStack.push(SystemIDResolver.getAbsoluteURI(this.getBaseIdentifier(), null)); |
| // initXPath(processor, null); |
| } |
| |
| /** |
| * Process an expression string into an XPath. |
| * Must be public for access by the AVT class. |
| * |
| * @param str A non-null reference to a valid or invalid XPath expression string. |
| * |
| * @return A non-null reference to an XPath object that represents the string argument. |
| * |
| * @throws javax.xml.transform.TransformerException if the expression can not be processed. |
| * @see <a href="http://www.w3.org/TR/xslt#section-Expressions">Section 4 Expressions in XSLT Specification</a> |
| */ |
| public XPath createXPath(String str, ElemTemplateElement owningTemplate) |
| throws javax.xml.transform.TransformerException |
| { |
| ErrorListener handler = m_stylesheetProcessor.getErrorListener(); |
| XPath xpath = new XPath(str, owningTemplate, this, XPath.SELECT, handler, |
| m_funcTable); |
| // Visit the expression, registering namespaces for any extension functions it includes. |
| xpath.callVisitors(xpath, new ExpressionVisitor(getStylesheetRoot())); |
| return xpath; |
| } |
| |
| /** |
| * Process an expression string into an XPath. |
| * |
| * @param str A non-null reference to a valid or invalid match pattern string. |
| * |
| * @return A non-null reference to an XPath object that represents the string argument. |
| * |
| * @throws javax.xml.transform.TransformerException if the pattern can not be processed. |
| * @see <a href="http://www.w3.org/TR/xslt#patterns">Section 5.2 Patterns in XSLT Specification</a> |
| */ |
| XPath createMatchPatternXPath(String str, ElemTemplateElement owningTemplate) |
| throws javax.xml.transform.TransformerException |
| { |
| ErrorListener handler = m_stylesheetProcessor.getErrorListener(); |
| XPath xpath = new XPath(str, owningTemplate, this, XPath.MATCH, handler, |
| m_funcTable); |
| // Visit the expression, registering namespaces for any extension functions it includes. |
| xpath.callVisitors(xpath, new ExpressionVisitor(getStylesheetRoot())); |
| return xpath; |
| } |
| |
| /** |
| * Given a namespace, get the corrisponding prefix from the current |
| * namespace support context. |
| * |
| * @param prefix The prefix to look up, which may be an empty string ("") for the default Namespace. |
| * |
| * @return The associated Namespace URI, or null if the prefix |
| * is undeclared in this context. |
| */ |
| public String getNamespaceForPrefix(String prefix) |
| { |
| return this.getNamespaceSupport().getURI(prefix); |
| } |
| |
| /** |
| * Given a namespace, get the corrisponding prefix. This is here only |
| * to support the {@link org.apache.xml.utils.PrefixResolver} interface, |
| * and will throw an error if invoked on this object. |
| * |
| * @param prefix The prefix to look up, which may be an empty string ("") for the default Namespace. |
| * @param context The node context from which to look up the URI. |
| * |
| * @return The associated Namespace URI, or null if the prefix |
| * is undeclared in this context. |
| */ |
| public String getNamespaceForPrefix(String prefix, org.w3c.dom.Node context) |
| { |
| |
| // Don't need to support this here. Return the current URI for the prefix, |
| // ignoring the context. |
| assertion(true, "can't process a context node in StylesheetHandler!"); |
| |
| return null; |
| } |
| |
| /** |
| * Utility function to see if the stack contains the given URL. |
| * |
| * @param stack non-null reference to a Stack. |
| * @param url URL string on which an equality test will be performed. |
| * |
| * @return true if the stack contains the url argument. |
| */ |
| private boolean stackContains(Stack stack, String url) |
| { |
| |
| int n = stack.size(); |
| boolean contains = false; |
| |
| for (int i = 0; i < n; i++) |
| { |
| String url2 = (String) stack.elementAt(i); |
| |
| if (url2.equals(url)) |
| { |
| contains = true; |
| |
| break; |
| } |
| } |
| |
| return contains; |
| } |
| |
| //////////////////////////////////////////////////////////////////// |
| // Implementation of the TRAX TemplatesBuilder interface. |
| //////////////////////////////////////////////////////////////////// |
| |
| /** |
| * When this object is used as a ContentHandler or ContentHandler, it will |
| * create a Templates object, which the caller can get once |
| * the SAX events have been completed. |
| * @return The stylesheet object that was created during |
| * the SAX event process, or null if no stylesheet has |
| * been created. |
| * |
| * Author <a href="mailto:scott_boag@lotus.com">Scott Boag</a> |
| * |
| * |
| */ |
| public Templates getTemplates() |
| { |
| return getStylesheetRoot(); |
| } |
| |
| /** |
| * Set the base ID (URL or system ID) for the stylesheet |
| * created by this builder. This must be set in order to |
| * resolve relative URLs in the stylesheet. |
| * |
| * @param baseID Base URL for this stylesheet. |
| */ |
| public void setSystemId(String baseID) |
| { |
| pushBaseIndentifier(baseID); |
| } |
| |
| /** |
| * Get the base ID (URI or system ID) from where relative |
| * URLs will be resolved. |
| * |
| * @return The systemID that was set with {@link #setSystemId}. |
| */ |
| public String getSystemId() |
| { |
| return this.getBaseIdentifier(); |
| } |
| |
| //////////////////////////////////////////////////////////////////// |
| // Implementation of the EntityResolver interface. |
| //////////////////////////////////////////////////////////////////// |
| |
| /** |
| * Resolve an external entity. |
| * |
| * @param publicId The public identifer, or null if none is |
| * available. |
| * @param systemId The system identifier provided in the XML |
| * document. |
| * @return The new input source, or null to require the |
| * default behaviour. |
| * |
| * @throws org.xml.sax.SAXException if the entity can not be resolved. |
| */ |
| public InputSource resolveEntity(String publicId, String systemId) |
| throws org.xml.sax.SAXException |
| { |
| return getCurrentProcessor().resolveEntity(this, publicId, systemId); |
| } |
| |
| //////////////////////////////////////////////////////////////////// |
| // Implementation of DTDHandler interface. |
| //////////////////////////////////////////////////////////////////// |
| |
| /** |
| * Receive notification of a notation declaration. |
| * |
| * <p>By default, do nothing. Application writers may override this |
| * method in a subclass if they wish to keep track of the notations |
| * declared in a document.</p> |
| * |
| * @param name The notation name. |
| * @param publicId The notation public identifier, or null if not |
| * available. |
| * @param systemId The notation system identifier. |
| * @see org.xml.sax.DTDHandler#notationDecl |
| */ |
| public void notationDecl(String name, String publicId, String systemId) |
| { |
| getCurrentProcessor().notationDecl(this, name, publicId, systemId); |
| } |
| |
| /** |
| * Receive notification of an unparsed entity declaration. |
| * |
| * @param name The entity name. |
| * @param publicId The entity public identifier, or null if not |
| * available. |
| * @param systemId The entity system identifier. |
| * @param notationName The name of the associated notation. |
| * @see org.xml.sax.DTDHandler#unparsedEntityDecl |
| */ |
| public void unparsedEntityDecl(String name, String publicId, |
| String systemId, String notationName) |
| { |
| getCurrentProcessor().unparsedEntityDecl(this, name, publicId, systemId, |
| notationName); |
| } |
| |
| /** |
| * Given a namespace URI, and a local name or a node type, get the processor |
| * for the element, or return null if not allowed. |
| * |
| * @param uri The Namespace URI, or an empty string. |
| * @param localName The local name (without prefix), or empty string if not namespace processing. |
| * @param rawName The qualified name (with prefix). |
| * |
| * @return A non-null reference to a element processor. |
| * |
| * @throws org.xml.sax.SAXException if the element is not allowed in the |
| * found position in the stylesheet. |
| */ |
| XSLTElementProcessor getProcessorFor( |
| String uri, String localName, String rawName) |
| throws org.xml.sax.SAXException |
| { |
| |
| XSLTElementProcessor currentProcessor = getCurrentProcessor(); |
| XSLTElementDef def = currentProcessor.getElemDef(); |
| XSLTElementProcessor elemProcessor = def.getProcessorFor(uri, localName); |
| |
| if (null == elemProcessor |
| && !(currentProcessor instanceof ProcessorStylesheetDoc) |
| && ((null == getStylesheet() |
| || Double.valueOf(getStylesheet().getVersion()).doubleValue() |
| > Constants.XSLTVERSUPPORTED) |
| ||(!uri.equals(Constants.S_XSLNAMESPACEURL) && |
| currentProcessor instanceof ProcessorStylesheetElement) |
| || getElemVersion() > Constants.XSLTVERSUPPORTED |
| )) |
| { |
| elemProcessor = def.getProcessorForUnknown(uri, localName); |
| } |
| |
| if (null == elemProcessor) |
| error(XSLMessages.createMessage(XSLTErrorResources.ER_NOT_ALLOWED_IN_POSITION, new Object[]{rawName}),null);//rawName + " is not allowed in this position in the stylesheet!", |
| |
| |
| return elemProcessor; |
| } |
| |
| //////////////////////////////////////////////////////////////////// |
| // Implementation of ContentHandler interface. |
| //////////////////////////////////////////////////////////////////// |
| |
| /** |
| * Receive a Locator object for document events. |
| * This is called by the parser to push a locator for the |
| * stylesheet being parsed. The stack needs to be popped |
| * after the stylesheet has been parsed. We pop in |
| * popStylesheet. |
| * |
| * @param locator A locator for all SAX document events. |
| * @see org.xml.sax.ContentHandler#setDocumentLocator |
| * @see org.xml.sax.Locator |
| */ |
| public void setDocumentLocator(Locator locator) |
| { |
| |
| // System.out.println("pushing locator for: "+locator.getSystemId()); |
| m_stylesheetLocatorStack.push(new SAXSourceLocator(locator)); |
| } |
| |
| /** |
| * The level of the stylesheet we are at. |
| */ |
| private int m_stylesheetLevel = -1; |
| |
| /** |
| * Receive notification of the beginning of the document. |
| * |
| * @see org.xml.sax.ContentHandler#startDocument |
| * |
| * @throws org.xml.sax.SAXException Any SAX exception, possibly |
| * wrapping another exception. |
| */ |
| public void startDocument() throws org.xml.sax.SAXException |
| { |
| m_stylesheetLevel++; |
| pushSpaceHandling(false); |
| } |
| |
| /** m_parsingComplete becomes true when the top-level stylesheet and all |
| * its included/imported stylesheets have been been fully parsed, as an |
| * indication that composition/optimization/compilation can begin. |
| * @see isStylesheetParsingComplete */ |
| private boolean m_parsingComplete = false; |
| |
| /** |
| * Test whether the _last_ endDocument() has been processed. |
| * This is needed as guidance for stylesheet optimization |
| * and compilation engines, which generally don't want to start |
| * until all included and imported stylesheets have been fully |
| * parsed. |
| * |
| * @return true iff the complete stylesheet tree has been built. |
| */ |
| public boolean isStylesheetParsingComplete() |
| { |
| return m_parsingComplete; |
| } |
| |
| /** |
| * Receive notification of the end of the document. |
| * |
| * @see org.xml.sax.ContentHandler#endDocument |
| * |
| * @throws org.xml.sax.SAXException Any SAX exception, possibly |
| * wrapping another exception. |
| */ |
| public void endDocument() throws org.xml.sax.SAXException |
| { |
| |
| try |
| { |
| if (null != getStylesheetRoot()) |
| { |
| if (0 == m_stylesheetLevel) |
| getStylesheetRoot().recompose(); |
| } |
| else |
| throw new TransformerException(XSLMessages.createMessage(XSLTErrorResources.ER_NO_STYLESHEETROOT, null)); //"Did not find the stylesheet root!"); |
| |
| XSLTElementProcessor elemProcessor = getCurrentProcessor(); |
| |
| if (null != elemProcessor) |
| elemProcessor.startNonText(this); |
| |
| m_stylesheetLevel--; |
| |
| popSpaceHandling(); |
| |
| // WARNING: This test works only as long as stylesheets are parsed |
| // more or less recursively. If we switch to an iterative "work-list" |
| // model, this will become true prematurely. In that case, |
| // isStylesheetParsingComplete() will have to be adjusted to be aware |
| // of the worklist. |
| m_parsingComplete = (m_stylesheetLevel < 0); |
| } |
| catch (TransformerException te) |
| { |
| throw new org.xml.sax.SAXException(te); |
| } |
| } |
| |
| private java.util.Vector m_prefixMappings = new java.util.Vector(); |
| |
| /** |
| * Receive notification of the start of a Namespace mapping. |
| * |
| * <p>By default, do nothing. Application writers may override this |
| * method in a subclass to take specific actions at the start of |
| * each element (such as allocating a new tree node or writing |
| * output to a file).</p> |
| * |
| * @param prefix The Namespace prefix being declared. |
| * @param uri The Namespace URI mapped to the prefix. |
| * @see org.xml.sax.ContentHandler#startPrefixMapping |
| * |
| * @throws org.xml.sax.SAXException Any SAX exception, possibly |
| * wrapping another exception. |
| */ |
| public void startPrefixMapping(String prefix, String uri) |
| throws org.xml.sax.SAXException |
| { |
| |
| // m_nsSupport.pushContext(); |
| // this.getNamespaceSupport().declarePrefix(prefix, uri); |
| //m_prefixMappings.add(prefix); // JDK 1.2+ only -sc |
| //m_prefixMappings.add(uri); // JDK 1.2+ only -sc |
| m_prefixMappings.addElement(prefix); // JDK 1.1.x compat -sc |
| m_prefixMappings.addElement(uri); // JDK 1.1.x compat -sc |
| } |
| |
| /** |
| * Receive notification of the end of a Namespace mapping. |
| * |
| * <p>By default, do nothing. Application writers may override this |
| * method in a subclass to take specific actions at the start of |
| * each element (such as allocating a new tree node or writing |
| * output to a file).</p> |
| * |
| * @param prefix The Namespace prefix being declared. |
| * @see org.xml.sax.ContentHandler#endPrefixMapping |
| * |
| * @throws org.xml.sax.SAXException Any SAX exception, possibly |
| * wrapping another exception. |
| */ |
| public void endPrefixMapping(String prefix) throws org.xml.sax.SAXException |
| { |
| |
| // m_nsSupport.popContext(); |
| } |
| |
| /** |
| * Flush the characters buffer. |
| * |
| * @throws org.xml.sax.SAXException |
| */ |
| private void flushCharacters() throws org.xml.sax.SAXException |
| { |
| |
| XSLTElementProcessor elemProcessor = getCurrentProcessor(); |
| |
| if (null != elemProcessor) |
| elemProcessor.startNonText(this); |
| } |
| |
| /** |
| * Receive notification of the start of an element. |
| * |
| * @param uri The Namespace URI, or an empty string. |
| * @param localName The local name (without prefix), or empty string if not namespace processing. |
| * @param rawName The qualified name (with prefix). |
| * @param attributes The specified or defaulted attributes. |
| * |
| * @throws org.xml.sax.SAXException |
| */ |
| public void startElement( |
| String uri, String localName, String rawName, Attributes attributes) |
| throws org.xml.sax.SAXException |
| { |
| NamespaceSupport nssupport = this.getNamespaceSupport(); |
| nssupport.pushContext(); |
| |
| int n = m_prefixMappings.size(); |
| |
| for (int i = 0; i < n; i++) |
| { |
| String prefix = (String)m_prefixMappings.elementAt(i++); |
| String nsURI = (String)m_prefixMappings.elementAt(i); |
| nssupport.declarePrefix(prefix, nsURI); |
| } |
| //m_prefixMappings.clear(); // JDK 1.2+ only -sc |
| m_prefixMappings.removeAllElements(); // JDK 1.1.x compat -sc |
| |
| m_elementID++; |
| |
| // This check is currently done for all elements. We should possibly consider |
| // limiting this check to xsl:stylesheet elements only since that is all it really |
| // applies to. Also, it could be bypassed if m_shouldProcess is already true. |
| // In other words, the next two statements could instead look something like this: |
| // if (!m_shouldProcess) |
| // { |
| // if (localName.equals(Constants.ELEMNAME_STYLESHEET_STRING) && |
| // url.equals(Constants.S_XSLNAMESPACEURL)) |
| // { |
| // checkForFragmentID(attributes); |
| // if (!m_shouldProcess) |
| // return; |
| // } |
| // else |
| // return; |
| // } |
| // I didn't include this code statement at this time because in practice |
| // it is a small performance hit and I was waiting to see if its absence |
| // caused a problem. - GLP |
| |
| checkForFragmentID(attributes); |
| |
| if (!m_shouldProcess) |
| return; |
| |
| flushCharacters(); |
| |
| pushSpaceHandling(attributes); |
| |
| XSLTElementProcessor elemProcessor = getProcessorFor(uri, localName, |
| rawName); |
| |
| if(null != elemProcessor) // defensive, for better multiple error reporting. -sb |
| { |
| this.pushProcessor(elemProcessor); |
| elemProcessor.startElement(this, uri, localName, rawName, attributes); |
| } |
| else |
| { |
| m_shouldProcess = false; |
| popSpaceHandling(); |
| } |
| |
| } |
| |
| /** |
| * Receive notification of the end of an element. |
| * |
| * @param uri The Namespace URI, or an empty string. |
| * @param localName The local name (without prefix), or empty string if not namespace processing. |
| * @param rawName The qualified name (with prefix). |
| * @see org.xml.sax.ContentHandler#endElement |
| * |
| * @throws org.xml.sax.SAXException Any SAX exception, possibly |
| * wrapping another exception. |
| */ |
| public void endElement(String uri, String localName, String rawName) |
| throws org.xml.sax.SAXException |
| { |
| |
| m_elementID--; |
| |
| if (!m_shouldProcess) |
| return; |
| |
| if ((m_elementID + 1) == m_fragmentID) |
| m_shouldProcess = false; |
| |
| flushCharacters(); |
| |
| popSpaceHandling(); |
| |
| XSLTElementProcessor p = getCurrentProcessor(); |
| |
| p.endElement(this, uri, localName, rawName); |
| this.popProcessor(); |
| this.getNamespaceSupport().popContext(); |
| } |
| |
| /** |
| * Receive notification of character data inside an element. |
| * |
| * @param ch The characters. |
| * @param start The start position in the character array. |
| * @param length The number of characters to use from the |
| * character array. |
| * @see org.xml.sax.ContentHandler#characters |
| * |
| * @throws org.xml.sax.SAXException Any SAX exception, possibly |
| * wrapping another exception. |
| */ |
| public void characters(char ch[], int start, int length) |
| throws org.xml.sax.SAXException |
| { |
| |
| if (!m_shouldProcess) |
| return; |
| |
| XSLTElementProcessor elemProcessor = getCurrentProcessor(); |
| XSLTElementDef def = elemProcessor.getElemDef(); |
| |
| if (def.getType() != XSLTElementDef.T_PCDATA) |
| elemProcessor = def.getProcessorFor(null, "text()"); |
| |
| if (null == elemProcessor) |
| { |
| |
| // If it's whitespace, just ignore it, otherwise flag an error. |
| if (!XMLCharacterRecognizer.isWhiteSpace(ch, start, length)) |
| error( |
| XSLMessages.createMessage(XSLTErrorResources.ER_NONWHITESPACE_NOT_ALLOWED_IN_POSITION, null),null);//"Non-whitespace text is not allowed in this position in the stylesheet!", |
| |
| } |
| else |
| elemProcessor.characters(this, ch, start, length); |
| } |
| |
| /** |
| * Receive notification of ignorable whitespace in element content. |
| * |
| * @param ch The whitespace characters. |
| * @param start The start position in the character array. |
| * @param length The number of characters to use from the |
| * character array. |
| * @see org.xml.sax.ContentHandler#ignorableWhitespace |
| * |
| * @throws org.xml.sax.SAXException Any SAX exception, possibly |
| * wrapping another exception. |
| */ |
| public void ignorableWhitespace(char ch[], int start, int length) |
| throws org.xml.sax.SAXException |
| { |
| |
| if (!m_shouldProcess) |
| return; |
| |
| getCurrentProcessor().ignorableWhitespace(this, ch, start, length); |
| } |
| |
| /** |
| * Receive notification of a processing instruction. |
| * |
| * <p>The Parser will invoke this method once for each processing |
| * instruction found: note that processing instructions may occur |
| * before or after the main document element.</p> |
| * |
| * <p>A SAX parser should never report an XML declaration (XML 1.0, |
| * section 2.8) or a text declaration (XML 1.0, section 4.3.1) |
| * using this method.</p> |
| * |
| * <p>By default, do nothing. Application writers may override this |
| * method in a subclass to take specific actions for each |
| * processing instruction, such as setting status variables or |
| * invoking other methods.</p> |
| * |
| * @param target The processing instruction target. |
| * @param data The processing instruction data, or null if |
| * none is supplied. |
| * @see org.xml.sax.ContentHandler#processingInstruction |
| * |
| * @throws org.xml.sax.SAXException Any SAX exception, possibly |
| * wrapping another exception. |
| */ |
| public void processingInstruction(String target, String data) |
| throws org.xml.sax.SAXException |
| { |
| if (!m_shouldProcess) |
| return; |
| |
| // Recreating Scott's kluge: |
| // A xsl:for-each or xsl:apply-templates may have a special |
| // PI that tells us not to cache the document. This PI |
| // should really be namespaced. |
| // String localName = getLocalName(target); |
| // String ns = m_stylesheet.getNamespaceFromStack(target); |
| // |
| // %REVIEW%: We need a better PI architecture |
| |
| String prefix="",ns="", localName=target; |
| int colon=target.indexOf(':'); |
| if(colon>=0) |
| { |
| ns=getNamespaceForPrefix(prefix=target.substring(0,colon)); |
| localName=target.substring(colon+1); |
| } |
| |
| try |
| { |
| // A xsl:for-each or xsl:apply-templates may have a special |
| // PI that tells us not to cache the document. This PI |
| // should really be namespaced... but since the XML Namespaces |
| // spec never defined namespaces as applying to PI's, and since |
| // the testcase we're trying to support is inconsistant in whether |
| // it binds the prefix, I'm going to make this sloppy for |
| // testing purposes. |
| if( |
| "xalan-doc-cache-off".equals(target) || |
| "xalan:doc-cache-off".equals(target) || |
| ("doc-cache-off".equals(localName) && |
| ns.equals("org.apache.xalan.xslt.extensions.Redirect") ) |
| ) |
| { |
| if(!(m_elems.peek() instanceof ElemForEach)) |
| throw new TransformerException |
| ("xalan:doc-cache-off not allowed here!", |
| getLocator()); |
| ElemForEach elem = (ElemForEach)m_elems.peek(); |
| |
| elem.m_doc_cache_off = true; |
| |
| //System.out.println("JJK***** Recognized <? {"+ns+"}"+prefix+":"+localName+" "+data+"?>"); |
| } |
| } |
| catch(Exception e) |
| { |
| // JJK: Officially, unknown PIs can just be ignored. |
| // Do we want to issue a warning? |
| } |
| |
| |
| flushCharacters(); |
| getCurrentProcessor().processingInstruction(this, target, data); |
| } |
| |
| /** |
| * Receive notification of a skipped entity. |
| * |
| * <p>By default, do nothing. Application writers may override this |
| * method in a subclass to take specific actions for each |
| * processing instruction, such as setting status variables or |
| * invoking other methods.</p> |
| * |
| * @param name The name of the skipped entity. |
| * @see org.xml.sax.ContentHandler#processingInstruction |
| * |
| * @throws org.xml.sax.SAXException Any SAX exception, possibly |
| * wrapping another exception. |
| */ |
| public void skippedEntity(String name) throws org.xml.sax.SAXException |
| { |
| |
| if (!m_shouldProcess) |
| return; |
| |
| getCurrentProcessor().skippedEntity(this, name); |
| } |
| |
| /** |
| * Warn the user of an problem. |
| * |
| * @param msg An key into the {@link org.apache.xalan.res.XSLTErrorResources} |
| * table, that is one of the WG_ prefixed definitions. |
| * @param args An array of arguments for the given warning. |
| * |
| * @throws org.xml.sax.SAXException that wraps a |
| * {@link javax.xml.transform.TransformerException} if the current |
| * {@link javax.xml.transform.ErrorListener#warning} |
| * method chooses to flag this condition as an error. |
| * @xsl.usage internal |
| */ |
| public void warn(String msg, Object args[]) throws org.xml.sax.SAXException |
| { |
| |
| String formattedMsg = XSLMessages.createWarning(msg, args); |
| SAXSourceLocator locator = getLocator(); |
| ErrorListener handler = m_stylesheetProcessor.getErrorListener(); |
| |
| try |
| { |
| if (null != handler) |
| handler.warning(new TransformerException(formattedMsg, locator)); |
| } |
| catch (TransformerException te) |
| { |
| throw new org.xml.sax.SAXException(te); |
| } |
| } |
| |
| /** |
| * Assert that a condition is true. If it is not true, throw an error. |
| * |
| * @param condition false if an error should not be thrown, otherwise true. |
| * @param msg Error message to be passed to the RuntimeException as an |
| * argument. |
| * @throws RuntimeException if the condition is not true. |
| * @xsl.usage internal |
| */ |
| private void assertion(boolean condition, String msg) throws RuntimeException |
| { |
| if (!condition) |
| throw new RuntimeException(msg); |
| } |
| |
| /** |
| * Tell the user of an error, and probably throw an |
| * exception. |
| * |
| * @param msg An error message. |
| * @param e An error which the SAXException should wrap. |
| * |
| * @throws org.xml.sax.SAXException that wraps a |
| * {@link javax.xml.transform.TransformerException} if the current |
| * {@link javax.xml.transform.ErrorListener#error} |
| * method chooses to flag this condition as an error. |
| * @xsl.usage internal |
| */ |
| protected void error(String msg, Exception e) |
| throws org.xml.sax.SAXException |
| { |
| |
| SAXSourceLocator locator = getLocator(); |
| ErrorListener handler = m_stylesheetProcessor.getErrorListener(); |
| TransformerException pe; |
| |
| if (!(e instanceof TransformerException)) |
| { |
| pe = (null == e) |
| ? new TransformerException(msg, locator) |
| : new TransformerException(msg, locator, e); |
| } |
| else |
| pe = (TransformerException) e; |
| |
| if (null != handler) |
| { |
| try |
| { |
| handler.error(pe); |
| } |
| catch (TransformerException te) |
| { |
| throw new org.xml.sax.SAXException(te); |
| } |
| } |
| else |
| throw new org.xml.sax.SAXException(pe); |
| } |
| |
| /** |
| * Tell the user of an error, and probably throw an |
| * exception. |
| * |
| * @param msg A key into the {@link org.apache.xalan.res.XSLTErrorResources} |
| * table, that is one of the WG_ prefixed definitions. |
| * @param args An array of arguments for the given warning. |
| * @param e An error which the SAXException should wrap. |
| * |
| * @throws org.xml.sax.SAXException that wraps a |
| * {@link javax.xml.transform.TransformerException} if the current |
| * {@link javax.xml.transform.ErrorListener#error} |
| * method chooses to flag this condition as an error. |
| * @xsl.usage internal |
| */ |
| protected void error(String msg, Object args[], Exception e) |
| throws org.xml.sax.SAXException |
| { |
| |
| String formattedMsg = XSLMessages.createMessage(msg, args); |
| |
| error(formattedMsg, e); |
| } |
| |
| /** |
| * Receive notification of a XSLT processing warning. |
| * |
| * @param e The warning information encoded as an exception. |
| * |
| * @throws org.xml.sax.SAXException that wraps a |
| * {@link javax.xml.transform.TransformerException} if the current |
| * {@link javax.xml.transform.ErrorListener#warning} |
| * method chooses to flag this condition as an error. |
| */ |
| public void warning(org.xml.sax.SAXParseException e) |
| throws org.xml.sax.SAXException |
| { |
| |
| String formattedMsg = e.getMessage(); |
| SAXSourceLocator locator = getLocator(); |
| ErrorListener handler = m_stylesheetProcessor.getErrorListener(); |
| |
| try |
| { |
| handler.warning(new TransformerException(formattedMsg, locator)); |
| } |
| catch (TransformerException te) |
| { |
| throw new org.xml.sax.SAXException(te); |
| } |
| } |
| |
| /** |
| * Receive notification of a recoverable XSLT processing error. |
| * |
| * @param e The error information encoded as an exception. |
| * |
| * @throws org.xml.sax.SAXException that wraps a |
| * {@link javax.xml.transform.TransformerException} if the current |
| * {@link javax.xml.transform.ErrorListener#error} |
| * method chooses to flag this condition as an error. |
| */ |
| public void error(org.xml.sax.SAXParseException e) |
| throws org.xml.sax.SAXException |
| { |
| |
| String formattedMsg = e.getMessage(); |
| SAXSourceLocator locator = getLocator(); |
| ErrorListener handler = m_stylesheetProcessor.getErrorListener(); |
| |
| try |
| { |
| handler.error(new TransformerException(formattedMsg, locator)); |
| } |
| catch (TransformerException te) |
| { |
| throw new org.xml.sax.SAXException(te); |
| } |
| } |
| |
| /** |
| * Report a fatal XSLT processing error. |
| * |
| * @param e The error information encoded as an exception. |
| * |
| * @throws org.xml.sax.SAXException that wraps a |
| * {@link javax.xml.transform.TransformerException} if the current |
| * {@link javax.xml.transform.ErrorListener#fatalError} |
| * method chooses to flag this condition as an error. |
| */ |
| public void fatalError(org.xml.sax.SAXParseException e) |
| throws org.xml.sax.SAXException |
| { |
| |
| String formattedMsg = e.getMessage(); |
| SAXSourceLocator locator = getLocator(); |
| ErrorListener handler = m_stylesheetProcessor.getErrorListener(); |
| |
| try |
| { |
| handler.fatalError(new TransformerException(formattedMsg, locator)); |
| } |
| catch (TransformerException te) |
| { |
| throw new org.xml.sax.SAXException(te); |
| } |
| } |
| |
| /** |
| * If we have a URL to a XML fragment, this is set |
| * to false until the ID is found. |
| * (warning: I worry that this should be in a stack). |
| */ |
| private boolean m_shouldProcess = true; |
| |
| /** |
| * If we have a URL to a XML fragment, the value is stored |
| * in this string, and the m_shouldProcess flag is set to |
| * false until we match an ID with this string. |
| * (warning: I worry that this should be in a stack). |
| */ |
| private String m_fragmentIDString; |
| |
| /** |
| * Keep track of the elementID, so we can tell when |
| * is has completed. This isn't a real ID, but rather |
| * a nesting level. However, it's good enough for |
| * our purposes. |
| * (warning: I worry that this should be in a stack). |
| */ |
| private int m_elementID = 0; |
| |
| /** |
| * The ID of the fragment that has been found |
| * (warning: I worry that this should be in a stack). |
| */ |
| private int m_fragmentID = 0; |
| |
| /** |
| * Check to see if an ID attribute matched the #id, called |
| * from startElement. |
| * |
| * @param attributes The specified or defaulted attributes. |
| */ |
| private void checkForFragmentID(Attributes attributes) |
| { |
| |
| if (!m_shouldProcess) |
| { |
| if ((null != attributes) && (null != m_fragmentIDString)) |
| { |
| int n = attributes.getLength(); |
| |
| for (int i = 0; i < n; i++) |
| { |
| String name = attributes.getQName(i); |
| |
| if (name.equals(Constants.ATTRNAME_ID)) |
| { |
| String val = attributes.getValue(i); |
| |
| if (val.equalsIgnoreCase(m_fragmentIDString)) |
| { |
| m_shouldProcess = true; |
| m_fragmentID = m_elementID; |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * The XSLT TransformerFactory for needed services. |
| */ |
| private TransformerFactoryImpl m_stylesheetProcessor; |
| |
| /** |
| * Get the XSLT TransformerFactoryImpl for needed services. |
| * TODO: This method should be renamed. |
| * |
| * @return The TransformerFactoryImpl that owns this handler. |
| */ |
| public TransformerFactoryImpl getStylesheetProcessor() |
| { |
| return m_stylesheetProcessor; |
| } |
| |
| /** |
| * If getStylesheetType returns this value, the current stylesheet |
| * is a root stylesheet. |
| * @xsl.usage internal |
| */ |
| public static final int STYPE_ROOT = 1; |
| |
| /** |
| * If getStylesheetType returns this value, the current stylesheet |
| * is an included stylesheet. |
| * @xsl.usage internal |
| */ |
| public static final int STYPE_INCLUDE = 2; |
| |
| /** |
| * If getStylesheetType returns this value, the current stylesheet |
| * is an imported stylesheet. |
| * @xsl.usage internal |
| */ |
| public static final int STYPE_IMPORT = 3; |
| |
| /** The current stylesheet type. */ |
| private int m_stylesheetType = STYPE_ROOT; |
| |
| /** |
| * Get the type of stylesheet that should be built |
| * or is being processed. |
| * |
| * @return one of STYPE_ROOT, STYPE_INCLUDE, or STYPE_IMPORT. |
| */ |
| int getStylesheetType() |
| { |
| return m_stylesheetType; |
| } |
| |
| /** |
| * Set the type of stylesheet that should be built |
| * or is being processed. |
| * |
| * @param type Must be one of STYPE_ROOT, STYPE_INCLUDE, or STYPE_IMPORT. |
| */ |
| void setStylesheetType(int type) |
| { |
| m_stylesheetType = type; |
| } |
| |
| /** |
| * The stack of stylesheets being processed. |
| */ |
| private Stack m_stylesheets = new Stack(); |
| |
| /** |
| * Return the stylesheet that this handler is constructing. |
| * |
| * @return The current stylesheet that is on top of the stylesheets stack, |
| * or null if no stylesheet is on the stylesheets stack. |
| */ |
| Stylesheet getStylesheet() |
| { |
| return (m_stylesheets.size() == 0) |
| ? null : (Stylesheet) m_stylesheets.peek(); |
| } |
| |
| /** |
| * Return the last stylesheet that was popped off the stylesheets stack. |
| * |
| * @return The last popped stylesheet, or null. |
| */ |
| Stylesheet getLastPoppedStylesheet() |
| { |
| return m_lastPoppedStylesheet; |
| } |
| |
| /** |
| * Return the stylesheet root that this handler is constructing. |
| * |
| * @return The root stylesheet of the stylesheets tree. |
| */ |
| public StylesheetRoot getStylesheetRoot() |
| { |
| if (m_stylesheetRoot != null){ |
| m_stylesheetRoot.setOptimizer(m_optimize); |
| m_stylesheetRoot.setIncremental(m_incremental); |
| m_stylesheetRoot.setSource_location(m_source_location); |
| } |
| return m_stylesheetRoot; |
| } |
| |
| /** The root stylesheet of the stylesheets tree. */ |
| StylesheetRoot m_stylesheetRoot; |
| |
| /** The last stylesheet that was popped off the stylesheets stack. */ |
| Stylesheet m_lastPoppedStylesheet; |
| |
| /** |
| * Push the current stylesheet being constructed. If no other stylesheets |
| * have been pushed onto the stack, assume the argument is a stylesheet |
| * root, and also set the stylesheet root member. |
| * |
| * @param s non-null reference to a stylesheet. |
| */ |
| public void pushStylesheet(Stylesheet s) |
| { |
| |
| if (m_stylesheets.size() == 0) |
| m_stylesheetRoot = (StylesheetRoot) s; |
| |
| m_stylesheets.push(s); |
| } |
| |
| /** |
| * Pop the last stylesheet pushed, and return the stylesheet that this |
| * handler is constructing, and set the last popped stylesheet member. |
| * Also pop the stylesheet locator stack. |
| * |
| * @return The stylesheet popped off the stack, or the last popped stylesheet. |
| */ |
| Stylesheet popStylesheet() |
| { |
| |
| // The stylesheetLocatorStack needs to be popped because |
| // a locator was pushed in for this stylesheet by the SAXparser by calling |
| // setDocumentLocator(). |
| if (!m_stylesheetLocatorStack.isEmpty()) |
| m_stylesheetLocatorStack.pop(); |
| |
| if (!m_stylesheets.isEmpty()) |
| m_lastPoppedStylesheet = (Stylesheet) m_stylesheets.pop(); |
| |
| // Shouldn't this be null if stylesheets is empty? -sb |
| return m_lastPoppedStylesheet; |
| } |
| |
| /** |
| * The stack of current processors. |
| */ |
| private Stack m_processors = new Stack(); |
| |
| /** |
| * Get the current XSLTElementProcessor at the top of the stack. |
| * |
| * @return Valid XSLTElementProcessor, which should never be null. |
| */ |
| XSLTElementProcessor getCurrentProcessor() |
| { |
| return (XSLTElementProcessor) m_processors.peek(); |
| } |
| |
| /** |
| * Push the current XSLTElementProcessor onto the top of the stack. |
| * |
| * @param processor non-null reference to the current element processor. |
| */ |
| void pushProcessor(XSLTElementProcessor processor) |
| { |
| m_processors.push(processor); |
| } |
| |
| /** |
| * Pop the current XSLTElementProcessor from the top of the stack. |
| * @return the XSLTElementProcessor which was popped. |
| */ |
| XSLTElementProcessor popProcessor() |
| { |
| return (XSLTElementProcessor) m_processors.pop(); |
| } |
| |
| /** |
| * The root of the XSLT Schema, which tells us how to |
| * transition content handlers, create elements, etc. |
| * For the moment at least, this can't be static, since |
| * the processors store state. |
| */ |
| private XSLTSchema m_schema = new XSLTSchema(); |
| |
| /** |
| * Get the root of the XSLT Schema, which tells us how to |
| * transition content handlers, create elements, etc. |
| * |
| * @return The root XSLT Schema, which should never be null. |
| * @xsl.usage internal |
| */ |
| public XSLTSchema getSchema() |
| { |
| return m_schema; |
| } |
| |
| /** |
| * The stack of elements, pushed and popped as events occur. |
| */ |
| private Stack m_elems = new Stack(); |
| |
| /** |
| * Get the current ElemTemplateElement at the top of the stack. |
| * @return Valid ElemTemplateElement, which may be null. |
| */ |
| ElemTemplateElement getElemTemplateElement() |
| { |
| |
| try |
| { |
| return (ElemTemplateElement) m_elems.peek(); |
| } |
| catch (java.util.EmptyStackException ese) |
| { |
| return null; |
| } |
| } |
| |
| /** An increasing number that is used to indicate the order in which this element |
| * was encountered during the parse of the XSLT tree. |
| */ |
| private int m_docOrderCount = 0; |
| |
| /** |
| * Returns the next m_docOrderCount number and increments the number for future use. |
| */ |
| int nextUid() |
| { |
| return m_docOrderCount++; |
| } |
| |
| /** |
| * Push the current XSLTElementProcessor to the top of the stack. As a |
| * side-effect, set the document order index (simply because this is a |
| * convenient place to set it). |
| * |
| * @param elem Should be a non-null reference to the intended current |
| * template element. |
| */ |
| void pushElemTemplateElement(ElemTemplateElement elem) |
| { |
| |
| if (elem.getUid() == -1) |
| elem.setUid(nextUid()); |
| |
| m_elems.push(elem); |
| } |
| |
| /** |
| * Get the current XSLTElementProcessor from the top of the stack. |
| * @return the ElemTemplateElement which was popped. |
| */ |
| ElemTemplateElement popElemTemplateElement() |
| { |
| return (ElemTemplateElement) m_elems.pop(); |
| } |
| |
| /** |
| * This will act as a stack to keep track of the |
| * current include base. |
| */ |
| Stack m_baseIdentifiers = new Stack(); |
| |
| /** |
| * Push a base identifier onto the base URI stack. |
| * |
| * @param baseID The current base identifier for this position in the |
| * stylesheet, which may be a fragment identifier, or which may be null. |
| * @see <a href="http://www.w3.org/TR/xslt#base-uri"> |
| * Section 3.2 Base URI of XSLT specification.</a> |
| */ |
| void pushBaseIndentifier(String baseID) |
| { |
| |
| if (null != baseID) |
| { |
| int posOfHash = baseID.indexOf('#'); |
| |
| if (posOfHash > -1) |
| { |
| m_fragmentIDString = baseID.substring(posOfHash + 1); |
| m_shouldProcess = false; |
| } |
| else |
| m_shouldProcess = true; |
| } |
| else |
| m_shouldProcess = true; |
| |
| m_baseIdentifiers.push(baseID); |
| } |
| |
| /** |
| * Pop a base URI from the stack. |
| * @return baseIdentifier. |
| */ |
| String popBaseIndentifier() |
| { |
| return (String) m_baseIdentifiers.pop(); |
| } |
| |
| /** |
| * Return the base identifier. |
| * |
| * @return The base identifier of the current stylesheet. |
| */ |
| public String getBaseIdentifier() |
| { |
| |
| // Try to get the baseIdentifier from the baseIdentifier's stack, |
| // which may not be the same thing as the value found in the |
| // SourceLocators stack. |
| String base = (String) (m_baseIdentifiers.isEmpty() |
| ? null : m_baseIdentifiers.peek()); |
| |
| // Otherwise try the stylesheet. |
| if (null == base) |
| { |
| SourceLocator locator = getLocator(); |
| |
| base = (null == locator) ? "" : locator.getSystemId(); |
| } |
| |
| return base; |
| } |
| |
| /** |
| * The top of this stack should contain the currently processed |
| * stylesheet SAX locator object. |
| */ |
| private Stack m_stylesheetLocatorStack = new Stack(); |
| |
| /** |
| * Get the current stylesheet Locator object. |
| * |
| * @return non-null reference to the current locator object. |
| */ |
| public SAXSourceLocator getLocator() |
| { |
| |
| if (m_stylesheetLocatorStack.isEmpty()) |
| { |
| SAXSourceLocator locator = new SAXSourceLocator(); |
| |
| locator.setSystemId(this.getStylesheetProcessor().getDOMsystemID()); |
| |
| return locator; |
| |
| // m_stylesheetLocatorStack.push(locator); |
| } |
| |
| return ((SAXSourceLocator) m_stylesheetLocatorStack.peek()); |
| } |
| |
| /** |
| * A stack of URL hrefs for imported stylesheets. This is |
| * used to diagnose circular imports. |
| */ |
| private Stack m_importStack = new Stack(); |
| |
| /** |
| * A stack of Source objects obtained from a URIResolver, |
| * for each element in this stack there is a 1-1 correspondence |
| * with an element in the m_importStack. |
| */ |
| private Stack m_importSourceStack = new Stack(); |
| |
| /** |
| * Push an import href onto the stylesheet stack. |
| * |
| * @param hrefUrl non-null reference to the URL for the current imported |
| * stylesheet. |
| */ |
| void pushImportURL(String hrefUrl) |
| { |
| m_importStack.push(hrefUrl); |
| } |
| |
| /** |
| * Push the Source of an import href onto the stylesheet stack, |
| * obtained from a URIResolver, null if there is no URIResolver, |
| * or if that resolver returned null. |
| */ |
| void pushImportSource(Source sourceFromURIResolver) |
| { |
| m_importSourceStack.push(sourceFromURIResolver); |
| } |
| |
| /** |
| * See if the imported stylesheet stack already contains |
| * the given URL. Used to test for recursive imports. |
| * |
| * @param hrefUrl non-null reference to a URL string. |
| * |
| * @return true if the URL is on the import stack. |
| */ |
| boolean importStackContains(String hrefUrl) |
| { |
| return stackContains(m_importStack, hrefUrl); |
| } |
| |
| /** |
| * Pop an import href from the stylesheet stack. |
| * |
| * @return non-null reference to the import URL that was popped. |
| */ |
| String popImportURL() |
| { |
| return (String) m_importStack.pop(); |
| } |
| |
| String peekImportURL() |
| { |
| return (String) m_importStack.peek(); |
| } |
| |
| Source peekSourceFromURIResolver() |
| { |
| return (Source) m_importSourceStack.peek(); |
| } |
| |
| /** |
| * Pop a Source from a user provided URIResolver, corresponding |
| * to the URL popped from the m_importStack. |
| */ |
| Source popImportSource() |
| { |
| return (Source) m_importSourceStack.pop(); |
| } |
| |
| /** |
| * If this is set to true, we've already warned about using the |
| * older XSLT namespace URL. |
| */ |
| private boolean warnedAboutOldXSLTNamespace = false; |
| |
| /** Stack of NamespaceSupport objects. */ |
| Stack m_nsSupportStack = new Stack(); |
| |
| /** |
| * Push a new NamespaceSupport instance. |
| */ |
| void pushNewNamespaceSupport() |
| { |
| m_nsSupportStack.push(new NamespaceSupport2()); |
| } |
| |
| /** |
| * Pop the current NamespaceSupport object. |
| * |
| */ |
| void popNamespaceSupport() |
| { |
| m_nsSupportStack.pop(); |
| } |
| |
| /** |
| * Get the current NamespaceSupport object. |
| * |
| * @return a non-null reference to the current NamespaceSupport object, |
| * which is the top of the namespace support stack. |
| */ |
| NamespaceSupport getNamespaceSupport() |
| { |
| return (NamespaceSupport) m_nsSupportStack.peek(); |
| } |
| |
| /** |
| * The originating node if the current stylesheet is being created |
| * from a DOM. |
| * @see org.apache.xml.utils.NodeConsumer |
| */ |
| private Node m_originatingNode; |
| |
| /** |
| * Set the node that is originating the SAX event. |
| * |
| * @param n Reference to node that originated the current event. |
| * @see org.apache.xml.utils.NodeConsumer |
| */ |
| public void setOriginatingNode(Node n) |
| { |
| m_originatingNode = n; |
| } |
| |
| /** |
| * Set the node that is originating the SAX event. |
| * |
| * @return Reference to node that originated the current event. |
| * @see org.apache.xml.utils.NodeConsumer |
| */ |
| public Node getOriginatingNode() |
| { |
| return m_originatingNode; |
| } |
| |
| /** |
| * Stack of booleans that are pushed and popped in start/endElement depending |
| * on the value of xml:space=default/preserve. |
| */ |
| private BoolStack m_spacePreserveStack = new BoolStack(); |
| |
| /** |
| * Return boolean value from the spacePreserve stack depending on the value |
| * of xml:space=default/preserve. |
| * |
| * @return true if space should be preserved, false otherwise. |
| */ |
| boolean isSpacePreserve() |
| { |
| return m_spacePreserveStack.peek(); |
| } |
| |
| /** |
| * Pop boolean value from the spacePreserve stack. |
| */ |
| void popSpaceHandling() |
| { |
| m_spacePreserveStack.pop(); |
| } |
| |
| /** |
| * Push boolean value on to the spacePreserve stack. |
| * |
| * @param b true if space should be preserved, false otherwise. |
| */ |
| void pushSpaceHandling(boolean b) |
| throws org.xml.sax.SAXParseException |
| { |
| m_spacePreserveStack.push(b); |
| } |
| |
| /** |
| * Push boolean value on to the spacePreserve stack depending on the value |
| * of xml:space=default/preserve. |
| * |
| * @param attrs list of attributes that were passed to startElement. |
| */ |
| void pushSpaceHandling(Attributes attrs) |
| throws org.xml.sax.SAXParseException |
| { |
| String value = attrs.getValue("xml:space"); |
| if(null == value) |
| { |
| m_spacePreserveStack.push(m_spacePreserveStack.peekOrFalse()); |
| } |
| else if(value.equals("preserve")) |
| { |
| m_spacePreserveStack.push(true); |
| } |
| else if(value.equals("default")) |
| { |
| m_spacePreserveStack.push(false); |
| } |
| else |
| { |
| SAXSourceLocator locator = getLocator(); |
| ErrorListener handler = m_stylesheetProcessor.getErrorListener(); |
| |
| try |
| { |
| handler.error(new TransformerException(XSLMessages.createMessage(XSLTErrorResources.ER_ILLEGAL_XMLSPACE_VALUE, null), locator)); //"Illegal value for xml:space", locator)); |
| } |
| catch (TransformerException te) |
| { |
| throw new org.xml.sax.SAXParseException(te.getMessage(), locator, te); |
| } |
| m_spacePreserveStack.push(m_spacePreserveStack.peek()); |
| } |
| } |
| |
| private double getElemVersion() |
| { |
| ElemTemplateElement elem = getElemTemplateElement(); |
| double version = -1; |
| while ((version == -1 || version == Constants.XSLTVERSUPPORTED) && elem != null) |
| { |
| try{ |
| version = Double.valueOf(elem.getXmlVersion()).doubleValue(); |
| } |
| catch (Exception ex) |
| { |
| version = -1; |
| } |
| elem = elem.getParentElem(); |
| } |
| return (version == -1)? Constants.XSLTVERSUPPORTED : version; |
| } |
| /** |
| * @see PrefixResolver#handlesNullPrefixes() |
| */ |
| public boolean handlesNullPrefixes() { |
| return false; |
| } |
| |
| /** |
| * @return Optimization flag |
| */ |
| public boolean getOptimize() { |
| return m_optimize; |
| } |
| |
| /** |
| * @return Incremental flag |
| */ |
| public boolean getIncremental() { |
| return m_incremental; |
| } |
| |
| /** |
| * @return Source Location flag |
| */ |
| public boolean getSource_location() { |
| return m_source_location; |
| } |
| |
| } |
| |
| |
| |