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

net.sf.saxon.functions.FunctionAvailable 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.functions;

import net.sf.saxon.expr.Expression;
import net.sf.saxon.expr.Literal;
import net.sf.saxon.expr.StaticContext;
import net.sf.saxon.expr.XPathContext;
import net.sf.saxon.expr.parser.ContextItemStaticInfo;
import net.sf.saxon.expr.parser.ExpressionVisitor;
import net.sf.saxon.lib.NamespaceConstant;
import net.sf.saxon.om.QNameParser;
import net.sf.saxon.om.Sequence;
import net.sf.saxon.om.StandardNames;
import net.sf.saxon.om.StructuredQName;
import net.sf.saxon.trans.SymbolicName;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.value.BooleanValue;
import net.sf.saxon.value.NumericValue;

/**
 * This class supports the XSLT element-available and function-available functions.
 */

public class FunctionAvailable extends SystemFunction {
    /**
     * Allow the function to create an optimized call based on the values of the actual arguments
     *
     * @param visitor     the expression visitor
     * @param contextInfo information about the context item
     * @param arguments   the supplied arguments to the function call
     * @return either a function call on this function, or an expression that delivers
     * the same result, or null indicating that no optimization has taken place
     * @throws net.sf.saxon.trans.XPathException if an error is detected
     */
    @Override
    public Expression makeOptimizedFunctionCall(ExpressionVisitor visitor, ContextItemStaticInfo contextInfo, Expression... arguments) throws XPathException {

        // Note, the LATE property is set in the function details to avoid the function being evaluated by the preEvaluate() call.
        // This is because the full static context is needed, not the (smaller) RetainedStaticContext. Instead, pre-evaluation
        // for calls with fixed arguments is done during the optimization phase, which makes the full static context available.

        if (arguments[0] instanceof Literal && (arguments.length == 1 || arguments[1] instanceof Literal)) {
            String lexicalQName = ((Literal) arguments[0]).getValue().getStringValue();
            StaticContext env = visitor.getStaticContext();
            boolean b = false;

            QNameParser qp = new QNameParser(env.getNamespaceResolver());
            qp.setAcceptEQName(true);
            qp.setDefaultNamespace(env.getDefaultFunctionNamespace());
            qp.setErrorOnBadSyntax("XTDE1400");
            qp.setErrorOnUnresolvedPrefix("XTDE1400");

            StructuredQName functionName = qp.parse(lexicalQName);

            int minArity = 0;
            int maxArity = 20;
            if (getArity() == 2) {
                minArity = (int) ((NumericValue) arguments[1].evaluateItem(env.makeEarlyEvaluationContext())).longValue();
                maxArity = minArity;
            }

            for (int i = minArity; i <= maxArity; i++) {
                SymbolicName sn = new SymbolicName(StandardNames.XSL_FUNCTION, functionName, i);
                if (env.getFunctionLibrary().isAvailable(sn)) {
                    b = true;
                    break;
                }
            }

            return Literal.makeLiteral(BooleanValue.get(b));
        } else {
            return null;
        }
    }

    private boolean isFunctionAvailable(String lexicalName, String edition, int arity, XPathContext context) throws XPathException {
        if (arity == -1) {
            for (int i = 0; i < 20; i++) {
                if (isFunctionAvailable(lexicalName, edition, i, context)) {
                    return true;
                }
            }
            return false;
        }
        StructuredQName qName;
        try {
            if (lexicalName.indexOf(':') < 0 && !lexicalName.startsWith("Q{")) {
                // we're in XSLT, where the default namespace for functions can't be changed
                String uri = NamespaceConstant.FN;
                qName = new StructuredQName("", uri, lexicalName);
            } else {
                boolean is30 = getRetainedStaticContext().getXPathVersion() >= 30;
                qName = StructuredQName.fromLexicalQName(lexicalName,
                        false, is30,
                        getRetainedStaticContext());
            }
        } catch (XPathException e) {
            e.setErrorCode("XTDE1400");
            e.setXPathContext(context);
            throw e;
        }

        final FunctionLibrary lib = context.getController().getExecutable().getFunctionLibrary();
        SymbolicName sn = new SymbolicName(StandardNames.XSL_FUNCTION, qName, arity);
        boolean known = lib.isAvailable(sn);
        if (known && sn.getComponentName().hasURI(NamespaceConstant.FN) && !context.getConfiguration().getEditionCode().equals(edition)) {
            // Target environment differs from compile-time environment: some functions might not be available
            StandardFunction.Entry details = StandardFunction.getFunction(sn.getComponentName().getLocalPart(), sn.getArity());
            if (details != null) {
                if (((details.applicability & StandardFunction.HOF) != 0) && ("HE".equals(edition) || "JS".equals(edition))) {
                    return false;
                }
                // TODO: some further functions are not available in Saxon-JS
            }
        }
        return known;
    }

    /**
     * Evaluate the expression
     *
     * @param context   the dynamic evaluation context
     * @param arguments the values of the arguments, supplied as SequenceIterators
     * @return the result of the evaluation, in the form of a SequenceIterator
     * @throws net.sf.saxon.trans.XPathException
     *          if a dynamic error occurs during the evaluation of the expression
     */
    public BooleanValue call(XPathContext context, Sequence[] arguments) throws XPathException {
        String lexicalQName = arguments[0].head().getStringValue();
        int arity = -1;
        if (arguments.length == 2) {
            arity = (int) ((NumericValue) arguments[1].head()).longValue();
        }
        return BooleanValue.get(
                isFunctionAvailable(lexicalQName, getRetainedStaticContext().getPackageData().getTargetEdition(), arity, context));
    }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy