/******************************************************************************* | |
* Copyright (c) 2008 Standards for Technology in Automotive Retail | |
* All rights reserved. This program and the accompanying materials | |
* are made available under the terms of the Eclipse Public License v1.0 | |
* which accompanies this distribution, and is available at | |
* http://www.eclipse.org/legal/epl-v10.html | |
* | |
* Contributors: | |
* David Carver - STAR - bug 224197 - initial API and implementation | |
* based on work from Apache Xalan 2.7.0 | |
*******************************************************************************/ | |
/* | |
* Copyright 1999-2004 The Apache Software Foundation. | |
* | |
* Licensed 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,v 1.3 2008/03/28 02:38:16 dacarver Exp $ | |
*/ | |
package org.eclipse.wst.xsl.core.internal.compiler.xslt10.processor; | |
import java.util.Stack; | |
import javax.xml.transform.ErrorListener; | |
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.eclipse.wst.xsl.core.internal.compiler.xslt10.extensions.ExpressionVisitor; | |
import org.apache.xalan.res.XSLMessages; | |
import org.apache.xalan.res.XSLTErrorResources; | |
import org.eclipse.wst.xsl.core.internal.compiler.xslt10.templates.Constants; | |
import org.eclipse.wst.xsl.core.internal.compiler.xslt10.templates.ElemForEach; | |
import org.eclipse.wst.xsl.core.internal.compiler.xslt10.templates.ElemTemplateElement; | |
import org.eclipse.wst.xsl.core.internal.compiler.xslt10.templates.Stylesheet; | |
import org.eclipse.wst.xsl.core.internal.compiler.xslt10.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.eclipse.wst.xsl.core.internal.compiler.xslt10.xpath.XPath; | |
import org.apache.xpath.compiler.FunctionTable; | |
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. | |
*/ | |
protected 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> | |
*/ | |
protected 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. | |
*/ | |
@Override | |
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 | |
*/ | |
@Override | |
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 | |
*/ | |
@Override | |
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. | |
*/ | |
public 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() > org.apache.xml.utils.Constants.XSLTVERSUPPORTED) | |
|| (!uri | |
.equals(org.apache.xml.utils.Constants.S_XSLNAMESPACEURL) && currentProcessor instanceof ProcessorStylesheetElement) || getElemVersion() > org.apache.xml.utils.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 | |
*/ | |
@Override | |
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. | |
*/ | |
@Override | |
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. | |
*/ | |
@Override | |
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. | |
*/ | |
@Override | |
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. | |
*/ | |
@Override | |
public void endPrefixMapping(String prefix) throws org.xml.sax.SAXException { | |
// m_nsSupport.popContext(); | |
} | |
/** | |
* Flush the characters buffer. | |
* | |
* @throws org.xml.sax.SAXException | |
*/ | |
public 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 | |
*/ | |
@Override | |
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. | |
*/ | |
@Override | |
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. | |
*/ | |
@Override | |
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. | |
*/ | |
@Override | |
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. | |
*/ | |
@Override | |
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; //$NON-NLS-1$//$NON-NLS-2$ | |
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) || //$NON-NLS-1$ | |
"xalan:doc-cache-off".equals(target) || //$NON-NLS-1$ | |
("doc-cache-off".equals(localName) && //$NON-NLS-1$ | |
ns.equals("org.apache.xalan.xslt.extensions.Redirect")) //$NON-NLS-1$ | |
) { | |
if (!(m_elems.peek() instanceof ElemForEach)) | |
throw new TransformerException( | |
"xalan:doc-cache-off not allowed here!", //$NON-NLS-1$ | |
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. | |
*/ | |
@Override | |
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 | |
*/ | |
public 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 | |
*/ | |
public 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. | |
*/ | |
@Override | |
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. | |
*/ | |
@Override | |
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. | |
*/ | |
@Override | |
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. | |
*/ | |
protected 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. | |
*/ | |
protected 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. | |
*/ | |
protected org.eclipse.wst.xsl.core.internal.compiler.xslt10.templates.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. | |
*/ | |
protected 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. | |
*/ | |
protected 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. | |
*/ | |
protected 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. | |
*/ | |
protected void pushProcessor(XSLTElementProcessor processor) { | |
m_processors.push(processor); | |
} | |
/** | |
* Pop the current XSLTElementProcessor from the top of the stack. | |
* | |
* @return the XSLTElementProcessor which was popped. | |
*/ | |
protected 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. | |
*/ | |
public 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. | |
*/ | |
public 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. | |
*/ | |
public 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. | |
*/ | |
public ElemTemplateElement popElemTemplateElement() { | |
return (ElemTemplateElement) m_elems.pop(); | |
} | |
/** | |
* This will act as a stack to keep track of the current include base. | |
*/ | |
protected 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> | |
*/ | |
public 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. | |
*/ | |
public 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(); | |
/** | |
* Push an import href onto the stylesheet stack. | |
* | |
* @param hrefUrl | |
* non-null reference to the URL for the current imported | |
* stylesheet. | |
*/ | |
public void pushImportURL(String hrefUrl) { | |
m_importStack.push(hrefUrl); | |
} | |
/** | |
* 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. | |
*/ | |
public 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. | |
*/ | |
public String popImportURL() { | |
return (String) m_importStack.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. */ | |
private Stack m_nsSupportStack = new Stack(); | |
/** | |
* Push a new NamespaceSupport instance. | |
*/ | |
public void pushNewNamespaceSupport() { | |
m_nsSupportStack.push(new NamespaceSupport2()); | |
} | |
/** | |
* Pop the current NamespaceSupport object. | |
* | |
*/ | |
public 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. | |
*/ | |
public 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. | |
*/ | |
public boolean isSpacePreserve() { | |
return m_spacePreserveStack.peek(); | |
} | |
/** | |
* Pop boolean value from the spacePreserve stack. | |
*/ | |
public void popSpaceHandling() { | |
m_spacePreserveStack.pop(); | |
} | |
/** | |
* Push boolean value on to the spacePreserve stack. | |
* | |
* @param b | |
* true if space should be preserved, false otherwise. | |
*/ | |
public 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. | |
*/ | |
public 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()); | |
} | |
} | |
public double getElemVersion() { | |
ElemTemplateElement elem = getElemTemplateElement(); | |
double version = -1; | |
while ((version == -1 || version == org.apache.xml.utils.Constants.XSLTVERSUPPORTED) | |
&& elem != null) { | |
try { | |
version = Double.valueOf(elem.getXmlVersion()).doubleValue(); | |
} catch (Exception ex) { | |
version = -1; | |
} | |
elem = elem.getParentElem(); | |
} | |
return (version == -1) ? org.apache.xml.utils.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; | |
} | |
} |