package client.net.sf.saxon.ce;
import client.net.sf.saxon.ce.event.CommentStripper;
import client.net.sf.saxon.ce.event.NamespaceReducer;
import client.net.sf.saxon.ce.event.PipelineConfiguration;
import client.net.sf.saxon.ce.event.StartTagBuffer;
import client.net.sf.saxon.ce.expr.instruct.Executable;
import client.net.sf.saxon.ce.expr.instruct.Template;
import client.net.sf.saxon.ce.om.CopyOptions;
import client.net.sf.saxon.ce.om.DocumentInfo;
import client.net.sf.saxon.ce.om.StructuredQName;
import client.net.sf.saxon.ce.style.*;
import client.net.sf.saxon.ce.trans.CompilerInfo;
import client.net.sf.saxon.ce.trans.DecimalFormatManager;
import client.net.sf.saxon.ce.trans.RuleManager;
import client.net.sf.saxon.ce.trans.XPathException;
import client.net.sf.saxon.ce.tree.linked.DocumentImpl;
import client.net.sf.saxon.ce.tree.linked.LinkedTreeBuilder;
import client.net.sf.saxon.ce.tree.util.Navigator;
import client.net.sf.saxon.ce.value.DecimalValue;
import java.util.HashMap;
/**
* This <B>PreparedStylesheet</B> class represents a Stylesheet that has been
* prepared for execution (or "compiled").
* <p/>
* 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 {
private CompilerInfo compilerInfo;
private transient StyleNodeFactory nodeFactory;
private int errorCount = 0;
// definitions of decimal formats
private DecimalFormatManager decimalFormatManager;
// definitions of template rules (XSLT only)
private RuleManager ruleManager;
// index of named templates.
private HashMap<StructuredQName, Template> namedTemplateTable;
/**
* Constructor
* @param config The Configuration set up by the TransformerFactory
* @param info Compilation options
*/
public PreparedStylesheet(Configuration config, CompilerInfo info) {
super(config);
nodeFactory = new StyleNodeFactory(config);
RuleManager rm = new RuleManager();
rm.setRecoveryPolicy(info.getRecoveryPolicy());
setRuleManager(rm);
compilerInfo = info;
}
/**
* Factory method to make a PreparedStylesheet
* @param url 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
*/
// public static PreparedStylesheet compile(String url, Configuration config, CompilerInfo info)
// throws XPathException {
// PreparedStylesheet pss = new PreparedStylesheet(config, info);
// pss.prepare(url);
// return pss;
// }
/**
* Make a Transformer from this Templates object.
* @return the new Transformer (always a Controller)
* @see client.net.sf.saxon.ce.Controller
*/
public Controller newTransformer() {
Controller c = new Controller(getConfiguration(), this);
c.setPreparedStylesheet(this);
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;
}
/**
* Prepare a stylesheet from a Source document
* @param doc the source document containing the stylesheet
* @throws XPathException if compilation of the stylesheet fails for any reason
*/
public void prepare(DocumentInfo doc) throws XPathException {
try {
setStylesheetDocument(loadStylesheetModule(doc));
} catch (XPathException e) {
// TODO: error handling
if (errorCount == 0) {
errorCount++;
}
throw e;
}
if (errorCount > 0) {
throw new XPathException(
"Failed to compile stylesheet. " +
errorCount +
(errorCount == 1 ? " error " : " errors ") +
"detected.");
}
}
/**
* Build the tree representation of a stylesheet module
* @param rawDoc the stylesheet module, typically as a DOM, before stripping of
* whitespace, comments, and PIs
* @return the root Document node of the tree containing the stylesheet
* module
* @throws XPathException if XML parsing or tree
* construction fails
*/
public DocumentImpl loadStylesheetModule(DocumentInfo rawDoc)
throws XPathException {
StyleNodeFactory nodeFactory = getStyleNodeFactory();
LinkedTreeBuilder styleBuilder = new LinkedTreeBuilder();
PipelineConfiguration pipe = getConfiguration().makePipelineConfiguration();
styleBuilder.setPipelineConfiguration(pipe);
styleBuilder.setSystemId(rawDoc.getSystemId());
styleBuilder.setNodeFactory(nodeFactory);
StartTagBuffer startTagBuffer = new StartTagBuffer();
NamespaceReducer nsReducer = new NamespaceReducer();
nsReducer.setUnderlyingReceiver(startTagBuffer);
UseWhenFilter useWhenFilter = new UseWhenFilter(startTagBuffer, nsReducer);
useWhenFilter.setUnderlyingReceiver(styleBuilder);
startTagBuffer.setUnderlyingReceiver(useWhenFilter);
StylesheetStripper styleStripper = new StylesheetStripper();
styleStripper.setUnderlyingReceiver(nsReducer);
CommentStripper commentStripper = new CommentStripper();
commentStripper.setUnderlyingReceiver(styleStripper);
commentStripper.setPipelineConfiguration(pipe);
// build the stylesheet document
commentStripper.open();
rawDoc.copy(commentStripper, CopyOptions.ALL_NAMESPACES);
commentStripper.close();
DocumentImpl doc = (DocumentImpl)styleBuilder.getCurrentRoot();
styleBuilder.reset();
return doc;
}
/**
* 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 == null) {
throw new XPathException("Failed to parse stylesheet");
}
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(DecimalValue.TWO) != 0) {
getConfiguration().issueWarning("Running an XSLT " + top.getEffectiveVersion() + " stylesheet with an XSLT 2.0 processor");
}
PrincipalStylesheetModule psm = new PrincipalStylesheetModule(top, 0);
psm.setPreparedStylesheet(this);
psm.setVersion(Navigator.getAttributeValue(top, "", "version"));
psm.createFunctionLibrary();
setFunctionLibrary(psm.getFunctionLibrary());
// Preprocess the stylesheet, performing validation and preparing template definitions
top.setPrincipalStylesheetModule(psm);
psm.preprocess();
// Compile the stylesheet, retaining the resulting executable
psm.compileStylesheet();
}
/**
* Get the associated executable
* @return the Executable for this stylesheet
*/
public Executable getExecutable() {
return this;
}
/**
* 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.
*/
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);
}
/**
* Report a compile time error. This calls the errorListener to output details
* of the error, and increments an error count.
* @param err the exception containing details of the error
* @throws XPathException if the ErrorListener decides that the
* error should be reported
*/
public void reportError(XPathException err) throws XPathException {
if (!err.hasBeenReported()) {
errorCount++;
compilerInfo.getErrorListener().error(err);
err.setHasBeenReported(true);
}
}
/**
* Get the number of errors reported so far
* @return the number of errors reported
*/
public int getErrorCount() {
return errorCount;
}
/**
* Report a compile time warning. This calls the errorListener to output details
* of the warning.
* @param err an exception holding details of the warning condition to be
* reported
*/
public void reportWarning(XPathException err) {
getConfiguration().issueWarning(err.getMessage());
}
/**
* Get the CompilerInfo containing details of XSLT compilation options
* @return the CompilerInfo containing compilation options
* @since 9.2
*/
public CompilerInfo getCompilerInfo() {
return compilerInfo;
}
//
// /**
// * Get the stylesheet specification(s) associated
// * via the xml-stylesheet processing instruction (see
// * http://www.w3.org/TR/xml-stylesheet/) with the document
// * document specified in the source parameter, and that match
// * the given criteria. Note that it is possible to return several
// * stylesheets, in which case they are applied as if they were
// * a list of imports or cascades.
// * @param config The Saxon Configuration
// * @param source The XML source document.
// * @param media The media attribute to be matched. May be null, in which
// * case the prefered templates will be used (i.e. alternate = no).
// * @param title The value of the title attribute to match. May be null.
// * @param charset The value of the charset attribute to match. May be null.
// * @return A Source object suitable for passing to the TransformerFactory.
// * @throws TransformerConfigurationException
// * if any problems occur
// */
//
//
// public static Source getAssociatedStylesheet(
// Configuration config, Source source, String media, String title, String charset)
// throws TransformerConfigurationException {
// PIGrabber grabber = new PIGrabber();
// grabber.setFactory(config);
// grabber.setCriteria(media, title, charset);
// grabber.setBaseURI(source.getSystemId());
// grabber.setURIResolver(config.getURIResolver());
// grabber.setPipelineConfiguration(config.makePipelineConfiguration());
//
// try {
// Sender.send(source, grabber, null);
// // this parse will be aborted when the first start tag is found
// } catch (XPathException err) {
// if (grabber.isTerminated()) {
// // do nothing
// } else {
// throw new TransformerConfigurationException(
// "Failed while looking for xml-stylesheet PI", err);
// }
// }
//
// try {
// Source[] sources = grabber.getAssociatedStylesheets();
// if (sources == null) {
// throw new TransformerConfigurationException(
// "No matching <?xml-stylesheet?> processing instruction found");
// }
// return compositeStylesheet(config, source.getSystemId(), sources);
// } catch (TransformerException err) {
// if (err instanceof TransformerConfigurationException) {
// throw (TransformerConfigurationException)err;
// } else {
// throw new TransformerConfigurationException(err);
// }
// }
// }
}
// 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.