net.sf.saxon.trans.RuleManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of Saxon-HE Show documentation
Show all versions of Saxon-HE Show documentation
The XSLT and XQuery Processor
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2015 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.trans;
import net.sf.saxon.Configuration;
import net.sf.saxon.expr.Component;
import net.sf.saxon.expr.XPathContext;
import net.sf.saxon.expr.instruct.TemplateRule;
import net.sf.saxon.expr.parser.ExpressionTool;
import net.sf.saxon.expr.parser.Token;
import net.sf.saxon.om.Item;
import net.sf.saxon.om.StructuredQName;
import net.sf.saxon.pattern.*;
import net.sf.saxon.style.StylesheetModule;
import net.sf.saxon.style.StylesheetPackage;
import net.sf.saxon.trace.ExpressionPresenter;
import java.util.Collection;
import java.util.HashMap;
/**
* RuleManager maintains a set of template rules, one set for each mode
*/
public final class RuleManager {
private StylesheetPackage stylesheetPackage;
private Configuration config;
private SimpleMode unnamedMode; // template rules with default mode
private HashMap modes;
// tables of rules for non-default modes
private SimpleMode omniMode = null; //template rules that specify mode="all"
private int recoveryPolicy;
private boolean unnamedModeExplicit;
private CompilerInfo compilerInfo; // We may need access to information on the compilation as distinct from the configuration
/**
* create a RuleManager and initialise variables.
*/
public RuleManager(StylesheetPackage pack) {
this.stylesheetPackage = pack;
this.config = pack.getConfiguration();
compilerInfo = config.getDefaultXsltCompilerInfo();
resetHandlers();
}
public RuleManager(StylesheetPackage pack, CompilerInfo compilerInfo) {
this.stylesheetPackage = pack;
this.config = pack.getConfiguration();
this.compilerInfo = compilerInfo;
resetHandlers();
}
/**
* Say that the unnamed mode has been explicitly declared in an xsl:mode declaration
*
* @param declared true if it has been explicitly declared
*/
public void setUnnamedModeExplicit(boolean declared) {
unnamedModeExplicit = declared;
}
/**
* Ask whether the unnamed mode has been explicitly declared in an xsl:mode declaration
*
* @return true if it has been explicitly declared
*/
public boolean isUnnamedModeExplicit() {
return unnamedModeExplicit;
}
/**
* Set the compiler information specifically.
*
* @param compilerInfo
*/
public void setCompilerInfo(CompilerInfo compilerInfo) {
this.compilerInfo = compilerInfo;
}
/**
* Set the policy for handling recoverable errors. Note that for some errors the decision can be
* made at run-time, but for the "ambiguous template match" error, the decision is (since 9.2)
* fixed at compile time.
*
* @param policy the recovery policy to be used. The options are {@link net.sf.saxon.Configuration#RECOVER_SILENTLY},
* {@link net.sf.saxon.Configuration#RECOVER_WITH_WARNINGS}, or {@link net.sf.saxon.Configuration#DO_NOT_RECOVER}.
* @since 9.2
*/
public void setRecoveryPolicy(int policy) {
recoveryPolicy = policy;
unnamedMode.setRecoveryPolicy(policy);
}
/**
* Get the policy for handling recoverable errors. Note that for some errors the decision can be
* made at run-time, but for the "ambiguous template match" error, the decision is (since 9.2)
* fixed at compile time.
*
* @return the current policy.
* @since 9.2
*/
public int getRecoveryPolicy() {
return recoveryPolicy;
}
/**
* Get all registered modes
*
* @return a collection containing all registered modes excluding the unnamed mode
*/
public Collection getAllNamedModes() {
return modes.values();
}
/**
* Set up a new table of handlers.
*/
public void resetHandlers() {
unnamedMode = config.makeMode(Mode.UNNAMED_MODE_NAME, compilerInfo);
Component c = unnamedMode.makeDeclaringComponent(Visibility.PRIVATE, stylesheetPackage);
stylesheetPackage.addComponent(c);
unnamedMode.setRecoveryPolicy(recoveryPolicy);
modes = new HashMap(5);
}
/**
* Get the mode object for the unnamed mode
*
* @return the unnamed mode
*/
/*@NotNull*/
public SimpleMode getUnnamedMode() {
return unnamedMode;
}
/**
* Get the Mode object for a named mode. If there is not one already registered.
* a new Mode is created. This uses a makeMode() method in the configuration
*
* @param modeName The name of the mode. Supply null to get the default
* mode or Mode.ALL_MODES to get the Mode object containing "mode=all" rules
* @param createIfAbsent if true, then if the mode does not already exist it will be created.
* If false, then if the mode does not already exist the method returns null.
* But if the requested mode is the omnimode, it is considered to always exist,
* and is therefore created regardless.
* @return the Mode with this name
*/
/*@Nullable*/
public Mode obtainMode(StructuredQName modeName, boolean createIfAbsent) {
if (modeName == null || modeName.equals(Mode.UNNAMED_MODE_NAME)) {
return unnamedMode;
}
if (modeName.equals(Mode.OMNI_MODE)) {
if (omniMode == null) {
omniMode = config.makeMode(modeName, compilerInfo);
omniMode.setRecoveryPolicy(recoveryPolicy);
}
return omniMode;
}
//Integer modekey = new Integer(modeNameCode & 0xfffff);
Mode m = modes.get(modeName);
if (m == null && createIfAbsent) {
m = config.makeMode(modeName, compilerInfo);
m.setRecoveryPolicy(recoveryPolicy);
// if (omniMode != null) {
// // when creating a specific mode, copy all the rules currently held
// // in the omniMode, as these apply to all modes
// Mode.copyRules(omniMode, m);
// }
modes.put(modeName, m);
Component c = m.makeDeclaringComponent(Visibility.PRIVATE, stylesheetPackage);
stylesheetPackage.addComponent(c);
}
return m;
}
public void registerMode(Mode mode) {
modes.put(mode.getModeName(), mode);
}
public boolean existsOmniMode() {
return omniMode != null;
}
/**
* Register a template for a particular pattern.
*
* @param pattern Must be a valid Pattern.
* @param eh The Template to be used
* @param mode The processing mode to which this template applies
* @param module The stylesheet module containing the template rule
* @param priority The priority of the rule: if an element matches several patterns, the
* one with highest priority is used
* @see Pattern
*/
public void setTemplateRule(Pattern pattern, TemplateRule eh,
Mode mode, StylesheetModule module, double priority) {
// for a union pattern, register the parts separately
// Note: technically this is only necessary if using default priorities and if the priorities
// of the two halves are different. However, splitting increases the chance that the pattern
// can be matched by hashing on the element name, so we do it always
if (pattern instanceof UnionPattern) {
UnionPattern up = (UnionPattern) pattern;
Pattern p1 = up.getLHS();
Pattern p2 = up.getRHS();
setTemplateRule(p1, eh, mode, module, priority);
setTemplateRule(p2, eh, mode, module, priority);
return;
}
// some union patterns end up as a CombinedNodeTest. Need to split these.
// (Same reasoning as above)
if (pattern instanceof NodeTestPattern &&
pattern.getItemType() instanceof CombinedNodeTest &&
((CombinedNodeTest) pattern.getItemType()).getOperator() == Token.UNION) {
CombinedNodeTest cnt = (CombinedNodeTest) pattern.getItemType();
NodeTest[] nt = cnt.getComponentNodeTests();
final NodeTestPattern nt0 = new NodeTestPattern(nt[0]);
ExpressionTool.copyLocationInfo(pattern, nt0);
setTemplateRule(nt0, eh, mode, module, priority);
final NodeTestPattern nt1 = new NodeTestPattern(nt[1]);
ExpressionTool.copyLocationInfo(pattern, nt1);
setTemplateRule(nt1, eh, mode, module, priority);
return;
}
if (Double.isNaN(priority)) {
priority = pattern.getDefaultPriority();
}
if (mode instanceof SimpleMode) {
((SimpleMode) mode).addRule(pattern, eh, module, module.getPrecedence(), priority, true);
} else {
mode.getActivePart().addRule(pattern, eh, module, mode.getMaxPrecedence(), priority, true);
}
}
/**
* Get the template rule matching a given item whose import precedence
* is in a particular range. This is used to support the xsl:apply-imports function
*
* @param item The item to be matched
* @param mode The mode for which a rule is required
* @param min The minimum import precedence that the rule must have
* @param max The maximum import precedence that the rule must have
* @param c The Controller for the transformation
* @return The template rule to be invoked
* @throws XPathException if an error occurs matching a pattern
*/
public Rule getTemplateRule(Item item, Mode mode, int min, int max, XPathContext c)
throws XPathException {
if (mode == null) {
mode = unnamedMode;
}
return mode.getRule(item, min, max, c);
}
/**
* Allocate rankings to the rules within each mode. This method must be called when all
* the rules in each mode are known. This method also checks that there are no conflicts for
* property values in different xsl:mode declarations
*
* @throws XPathException if an error occurs
*/
public void computeRankings() throws XPathException {
unnamedMode.computeRankings(0);
for (Mode mode : modes.values()) {
mode.computeRankings(0);
}
}
/**
* Invert streamable templates in all streamable modes
*
* @throws XPathException if the templates are not streamable
*/
public void invertStreamableTemplates() throws XPathException {
unnamedMode.invertStreamableTemplates();
for (Mode mode : modes.values()) {
mode.getActivePart().invertStreamableTemplates();
}
}
/**
* Check all modes for conflicts in property values
*
* @throws XPathException if a mode has conflicting property values
*/
public void checkConsistency() throws XPathException {
unnamedMode.checkForConflictingProperties();
for (Mode mode : modes.values()) {
mode.getActivePart().checkForConflictingProperties();
}
}
/**
* Explain (that is, output the expression tree) for all template rules
*
* @param presenter the object used to present the output
*/
public void exportTemplateRules(ExpressionPresenter presenter) throws XPathException {
unnamedMode.export(presenter);
for (Mode mode : modes.values()) {
mode.export(presenter);
}
}
/**
* Explain (that is, output the expression tree) for all template rules
*
* @param presenter the object used to present the output
*/
public void explainTemplateRules(ExpressionPresenter presenter) throws XPathException {
unnamedMode.explain(presenter);
for (Mode mode : modes.values()) {
mode.explain(presenter);
}
}
/**
* Optimization of template rules
* Only invoked when rule optimization has been turned on.
* In this case we know the modes are instances of at least ModeEE
*/
public void optimizeRules() {
PatternOptimization patternOptimization = compilerInfo.getPatternOptimization();
if (patternOptimization != null && patternOptimization.isOptimize()) {
unnamedMode.optimizeRules();
for (Mode mode : modes.values()) {
mode.getActivePart().optimizeRules();
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy