在我的应用程序中,使用 Saxon,我想检测 XPath 表达式是否访问上下文项而不实际执行该表达式。也就是说,尝试在没有上下文项的情况下计算表达式是否会导致错误XPDY0002?
这是我迄今为止最好的尝试,但我想知道我是否错过了更简单的方法:
public static void main(final String[] args) throws SaxonApiException {
Processor saxonProc = new Processor(false);
XPathCompiler compiler = saxonProc.newXPathCompiler();
// How to tell statically that these two access the context item...
XPathExecutable e1 = compiler.compile("//foo/bar");
System.err.println("e1: " + accessesContextItem(e1));
XPathExecutable e2 = compiler.compile(". eq 23");
System.err.println("e2: " + accessesContextItem(e2));
// ..and this one doesn't?
XPathExecutable e3 = compiler.compile("'standalone string expression with no context item access'");
System.err.println("e3: " + accessesContextItem(e3));
}
private static boolean accessesContextItem(final XPathExecutable ex) {
return containsContextAccess(ex.getUnderlyingExpression().getInternalExpression());
}
private static final Set<Class<? extends Expression>> KNOWN_TO_ACCESS_CONTEXT_ITEM = new LinkedHashSet<Class<? extends Expression>>();
static {
KNOWN_TO_ACCESS_CONTEXT_ITEM.add(AxisExpression.class);
KNOWN_TO_ACCESS_CONTEXT_ITEM.add(ContextItemExpression.class);
KNOWN_TO_ACCESS_CONTEXT_ITEM.add(ParentNodeExpression.class);
KNOWN_TO_ACCESS_CONTEXT_ITEM.add(RootExpression.class);
KNOWN_TO_ACCESS_CONTEXT_ITEM.add(SingleNodeExpression.class);
}
private static boolean containsContextAccess(final Expression ex) {
boolean thisExDoes = KNOWN_TO_ACCESS_CONTEXT_ITEM.contains(ex.getClass());
if (thisExDoes) {
return true;
}
// check descendants
return Iterators.any(ex.iterateSubExpressions(), new Predicate<Expression>() {
public boolean apply(final Expression child) {
return containsContextAccess(child);
}
});
}
这可以通过以下代码片段(使用 Saxon 9.3)相对容易地完成。
import net.sf.saxon.expr.StaticProperty;
import net.sf.saxon.expr.StringLiteral;
import net.sf.saxon.sxpath.IndependentContext;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.om.StructuredQName;
import net.sf.saxon.expr.Expression;
import net.sf.saxon.expr.ExpressionParser;
public boolean dependsOnContext(final String expression) {
final ExpressionParser expressionParser = new ExpressionParser();
final IndependentContext context = new IndependentContext() {
@Override
public Expression bindVariable(final StructuredQName qName) throws XPathException {
try {
return super.bindVariable(qName);
}
catch (XPathException e) {
//This assumes no variables are bound since no configuration is supplied to IndependentContext
return new StringLiteral("Dummy");
}
}
};
try {
Expression parsedExpression = expressionParser.parse(expression, 0, Token.EOF, -1, context);
return ((parsedExpression.getDependencies() & (StaticProperty.DEPENDS_ON_CONTEXT_DOCUMENT | StaticProperty.DEPENDS_ON_CONTEXT_ITEM)) == 0);
}
catch (XPathException e) {
//Handle XPath exception if expression is malformed
}
}