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

net.sf.saxon.trans.RuleManager Maven / Gradle / Ivy

There is a newer version: 12.5
Show newest version
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 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