Saxon:静态检测 XPath 表达式是否访问上下文项



在我的应用程序中,使用 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
  }
}

最新更新