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