All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.saxon.PreparedStylesheet Maven / Gradle / Ivy

There is a newer version: 10.5
Show newest version
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2013 Saxonica Limited.
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package net.sf.saxon;

import net.sf.saxon.event.*;
import net.sf.saxon.expr.instruct.Executable;
import net.sf.saxon.expr.instruct.GlobalParameterSet;
import net.sf.saxon.expr.instruct.Template;
import net.sf.saxon.expr.instruct.UserFunction;
import net.sf.saxon.functions.ExecutableFunctionLibrary;
import net.sf.saxon.functions.FunctionLibrary;
import net.sf.saxon.functions.FunctionLibraryList;
import net.sf.saxon.lib.AugmentedSource;
import net.sf.saxon.lib.NamespaceConstant;
import net.sf.saxon.lib.ParseOptions;
import net.sf.saxon.lib.Validation;
import net.sf.saxon.om.StructuredQName;
import net.sf.saxon.om.StylesheetSpaceStrippingRule;
import net.sf.saxon.style.*;
import net.sf.saxon.trace.ExpressionPresenter;
import net.sf.saxon.trans.*;
import net.sf.saxon.tree.linked.DocumentImpl;
import net.sf.saxon.tree.linked.LinkedTreeBuilder;
import net.sf.saxon.value.DecimalValue;
import net.sf.saxon.value.Whitespace;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;

import javax.xml.transform.*;
import javax.xml.transform.sax.SAXSource;
import java.io.Serializable;
import java.io.StringReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;

/**
 * This PreparedStylesheet class represents a Stylesheet that has been
 * prepared for execution (or "compiled").
 * 

* Note that the PreparedStylesheet object does not contain a reference to the source stylesheet * tree (rooted at an XSLStyleSheet object). This allows the source tree to be garbage-collected * when it is no longer required. */ public class PreparedStylesheet extends Executable implements Templates, Serializable { private CompilerInfo compilerInfo; private transient StyleNodeFactory nodeFactory; private int errorCount = 0; private HashMap nextStylesheetCache; // cache for stylesheets named as "saxon:next-in-chain" // definitions of decimal formats private DecimalFormatManager decimalFormatManager; // definitions of template rules (XSLT only) private RuleManager ruleManager; // index of named templates. private HashMap namedTemplateTable; // a boolean flag indicating whether the stylesheet makes any use of tunnel parameters private boolean usesTunnel = false; // manager class for accumulator rules (XSLT 3.0 only) private IAccumulatorManager accumulatorManager = null; // manager list of variables coming from xsl:param and xsl:variable relating to statis attribute private GlobalParameterSet variableList = new GlobalParameterSet(); /** * Constructor - deliberately protected * @param config The Configuration set up by the TransformerFactory * @param info Compilation options */ protected PreparedStylesheet(Configuration config, CompilerInfo info) { super(config); nodeFactory = config.makeStyleNodeFactory(); nodeFactory.setXsltProcessorVersion(info.getXsltVersion()); nodeFactory.makeAccumulatorManager(this); RuleManager rm = new RuleManager(); rm.setRecoveryPolicy(info.getRecoveryPolicy()); setRuleManager(rm); setHostLanguage(Configuration.XSLT, info.getXsltVersion().equals(DecimalValue.THREE)); setCollationMap(info.getCollationMap()); setSchemaAware(info.isSchemaAware()); compilerInfo = info; if (compilerInfo.getErrorListener() == null) { compilerInfo.setErrorListener(config.getErrorListener()); } } /** * Factory method to make a PreparedStylesheet * @param source the source of this principal stylesheet module * @param config the Saxon configuration * @param info compile-time options for this stylesheet compilation * @return the prepared stylesheet * @throws javax.xml.transform.TransformerConfigurationException if there is a static error in the stylesheet */ public static PreparedStylesheet compile(Source source, Configuration config, CompilerInfo info) throws TransformerConfigurationException { PreparedStylesheet pss = new PreparedStylesheet(config, info); pss.prepare(source); return pss; } /** * Make a Transformer from this Templates object. * @return the new Transformer (always a Controller) * @see net.sf.saxon.Controller */ public Transformer newTransformer() { Controller c = new Controller(getConfiguration(), this); c.setPreparedStylesheet(this); c.setRecoveryPolicy(compilerInfo.getRecoveryPolicy()); if (compilerInfo.getDefaultInitialTemplate() != null) { try { c.setInitialTemplate(compilerInfo.getDefaultInitialTemplate().getClarkName()); } catch (XPathException err) { // ignore error if there is no template with this name } } if (compilerInfo.getDefaultInitialMode() != null) { c.setInitialMode(compilerInfo.getDefaultInitialMode().getClarkName()); } return c; } /** * Set the configuration in which this stylesheet is compiled. * Intended for internal use. * @param config the configuration to be used. */ public void setConfiguration(Configuration config) { super.setConfiguration(config); this.compilerInfo = config.getDefaultXsltCompilerInfo(); } /** * Get the StyleNodeFactory in use. The StyleNodeFactory determines which subclass of StyleElement * to use for each element node in the stylesheet tree. * @return the StyleNodeFactory */ public StyleNodeFactory getStyleNodeFactory() { return nodeFactory; } /** * Set the DecimalFormatManager which handles decimal-format definitions * @param dfm the DecimalFormatManager containing the named xsl:decimal-format definitions */ public void setDecimalFormatManager(DecimalFormatManager dfm) { decimalFormatManager = dfm; } /** * Get the DecimalFormatManager which handles decimal-format definitions * @return the DecimalFormatManager containing the named xsl:decimal-format definitions */ public DecimalFormatManager getDecimalFormatManager() { if (decimalFormatManager == null) { decimalFormatManager = new DecimalFormatManager(); } return decimalFormatManager; } /** * Get the class that manages accumulator functions * @return the class that manages accumulators. Always null in Saxon-HE */ public IAccumulatorManager getAccumulatorManager() { return accumulatorManager; } /** * Set the class that manages accumulator functions * @param accumulatorManager the manager of accumulator functions */ public void setAccumulatorManager(IAccumulatorManager accumulatorManager) { this.accumulatorManager = accumulatorManager; } /** * Say that the stylesheet uses tunnel parameters. (This information is used by the bytecode generator, * which avoids generating code to pass tunnel parameters on every apply-templates call if there are no * tunnel parameters anywhere in the stylesheet). */ public void setUsesTunnelParameters() { usesTunnel = true; } /** * Ask whether the stylesheet uses tunnel parameters. (Called by the bytecode generator). * @return true if the stylesheet uses tunnel parameters. */ public boolean usesTunnelParameters() { return usesTunnel; } /** * Prepare a stylesheet from a Source document * @param styleSource the source document containing the stylesheet * @throws TransformerConfigurationException * if compilation of the * stylesheet fails for any reason */ protected void prepare(Source styleSource) throws TransformerConfigurationException { DocumentImpl doc; try { doc = loadStylesheetModule(styleSource); setStylesheetDocument(doc); } catch (XPathException e) { try { compilerInfo.getErrorListener().fatalError(e); } catch (TransformerException e2) { // ignore an exception thrown by the error handler } if (errorCount == 0) { errorCount++; } } if (errorCount > 0) { throw new TransformerConfigurationException( "Failed to compile stylesheet. " + errorCount + (errorCount == 1 ? " error " : " errors ") + "detected."); } } /** * Build the tree representation of a stylesheet module * @param styleSource the source of the module * @return the root Document node of the tree containing the stylesheet * module * @throws XPathException if XML parsing or tree * construction fails */ public DocumentImpl loadStylesheetModule(Source styleSource) throws XPathException { StyleNodeFactory nodeFactory = getStyleNodeFactory(); PipelineConfiguration pipe = getConfiguration().makePipelineConfiguration(); LinkedTreeBuilder styleBuilder = new LinkedTreeBuilder(pipe); pipe.setURIResolver(compilerInfo.getURIResolver()); pipe.setErrorListener(compilerInfo.getErrorListener()); styleBuilder.setSystemId(styleSource.getSystemId()); styleBuilder.setNodeFactory(nodeFactory); styleBuilder.setLineNumbering(true); UseWhenFilter useWhenFilter = new UseWhenFilter(this, styleBuilder); StartTagBuffer startTagBuffer = new StartTagBuffer(useWhenFilter); useWhenFilter.setStartTagBuffer(startTagBuffer); StylesheetSpaceStrippingRule rule = new StylesheetSpaceStrippingRule(getConfiguration().getNamePool()); Stripper styleStripper = new Stripper(rule, startTagBuffer); CommentStripper commentStripper = new CommentStripper(styleStripper); // build the stylesheet document DocumentImpl doc; ParseOptions options; if (styleSource instanceof AugmentedSource) { options = ((AugmentedSource)styleSource).getParseOptions(); styleSource = ((AugmentedSource)styleSource).getContainedSource(); } else { options = new ParseOptions(); } options.setErrorListener(compilerInfo.getErrorListener()); options.setSchemaValidationMode(Validation.STRIP); options.setDTDValidationMode(Validation.STRIP); options.setLineNumbering(true); options.setStripSpace(Whitespace.NONE); try { if (options.getXMLReader() == null && Configuration.getPlatform().isJava()) { XMLReader styleParser = getConfiguration().getStyleParser(); options.setXMLReader(styleParser); Sender.send(styleSource, commentStripper, options); getConfiguration().reuseStyleParser(styleParser); } else { Sender.send(styleSource, commentStripper, options); } doc = (DocumentImpl)styleBuilder.getCurrentRoot(); styleBuilder.reset(); return doc; } finally { if (options.isPleaseCloseAfterUse()) { ParseOptions.close(styleSource); } } } /** * Create a PreparedStylesheet from a supplied DocumentInfo * Note: the document must have been built using the StyleNodeFactory * @param doc the document containing the stylesheet module * @throws XPathException if the document supplied * is not a stylesheet */ protected void setStylesheetDocument(DocumentImpl doc) throws XPathException { DocumentImpl styleDoc = doc; // If top-level node is a literal result element, stitch it into a skeleton stylesheet StyleElement topnode = (StyleElement)styleDoc.getDocumentElement(); if (topnode instanceof LiteralResultElement) { styleDoc = ((LiteralResultElement)topnode).makeStylesheet(this); } if (!(styleDoc.getDocumentElement() instanceof XSLStylesheet)) { throw new XPathException( "Outermost element of stylesheet is not xsl:stylesheet or xsl:transform or literal result element"); } XSLStylesheet top = (XSLStylesheet)styleDoc.getDocumentElement(); if (compilerInfo.isVersionWarning() && top.getEffectiveVersion().compareTo(getStyleNodeFactory().getXsltProcessorVersion()) != 0) { try { TransformerException w = new TransformerException( "Running an XSLT " + top.getEffectiveVersion() + " stylesheet with an XSLT " + getStyleNodeFactory().getXsltProcessorVersion() + " processor"); w.setLocator(topnode); getConfiguration().getErrorListener().warning(w); } catch (TransformerException e) { throw XPathException.makeXPathException(e); } } if (getStyleNodeFactory().getXsltProcessorVersion().compareTo(DecimalValue.TWO) > 0) { // The condition is checked again later in non-open code, but we can give a better error message here getConfiguration().checkLicensedFeature(Configuration.LicenseFeature.PROFESSIONAL_EDITION, "XSLT 3.0"); } PrincipalStylesheetModule psm = new PrincipalStylesheetModule(top, 0); psm.setPreparedStylesheet(this); psm.setVersion(top.getAttributeValue("version")); psm.createFunctionLibrary(compilerInfo); // Preprocess the stylesheet, performing validation and preparing template definitions //executable.setLocationMap(psm.getLocationMap()); top.setPrincipalStylesheetModule(psm); try { psm.preprocess(); } catch (XPathException e) { Throwable e2 = e.getException(); if (e2 instanceof XPathException) { try { compilerInfo.getErrorListener().fatalError((XPathException)e2); } catch (TransformerException e3) { // ignore an error thrown by the ErrorListener } } throw e; } // Compile the stylesheet, retaining the resulting executable psm.compileStylesheet(); } /** * Set the RuleManager that handles template rules * * @param rm the RuleManager containing details of all the template rules */ public void setRuleManager(RuleManager rm) { ruleManager = rm; } /** * Get the RuleManager which handles template rules * * @return the RuleManager registered with setRuleManager */ public RuleManager getRuleManager() { return ruleManager; } /** * Get the named template with a given name. * * @param qName The template name * @return The template (of highest import precedence) with this name if there is one; * null if none is found. */ /*@Nullable*/ public Template getNamedTemplate(StructuredQName qName) { if (namedTemplateTable == null) { return null; } return namedTemplateTable.get(qName); } /** * Register the named template with a given name * @param templateName the name of a named XSLT template * @param template the template */ public void putNamedTemplate(StructuredQName templateName, Template template) { if (namedTemplateTable == null) { namedTemplateTable = new HashMap(32); } namedTemplateTable.put(templateName, template); } /** * Iterate over all the named templates defined in this Executable * @return an iterator, the items returned being of class {@link net.sf.saxon.expr.instruct.Template} */ public Iterator