问题描述
虽然我使用Saxon Java api执行以下xQuery,但我无法理解为什么以下执行/验证失败? (有趣的是,当我在if语句中用and
替换or
子句时,查询验证成功,但无法理解此行为)
在氧气xml验证器中,当我打开xQuery时,出现NullPointerException-null
异常,验证失败。
在Java中,我得到以下区域
java.lang.NullPointerException
at net.sf.saxon.expr.parser.LoopLifter.markDependencies(LoopLifter.java:168)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:112)
我正在寻找一些专家来帮助我理解以下原因失败的原因。
以下是xQuery,
declare function local:method($input as element(input)) as element(output)
{
<output>
<itemADetails>
<service>
{
for $i in 1 to count($input/*:foo)
return
for $j in 1 to count($input/*:bar)
return
if((data($input/*:foo[$i]/*:itemB[1]/*:rangeQualifier)="A") and (data($input/*:foo[$i]/*:serviceId/*:type)="B") ) then
<node></node>
else()
}
</service>
</itemADetails>
</output>
};
declare variable $input as element(input) external;
local:method($input)
Saxon Verion
implementation 'net.sf.saxon:Saxon-HE:10.2'
implementation 'net.sf.saxon:saxon-xqj:9.1.0.8'
我尝试过的示例代码段
Processor saxon = new Processor(false);
// compile the query
XQueryCompiler compiler = saxon.newXQueryCompiler();
XQueryExecutable exec;
ClassLoader classLoader = MessageProcessor.class.getClassLoader();
exec = compiler.compile(new File(classLoader.getResource("Xquery.xqy").getFile()));
Source src = new StreamSource(new StringReader(Files.readString( Paths.get(ClassLoader.getSystemResource(inputfile.xml").toURI()))));
XdmNode doc = builder.build(src);
// instantiate the query,bind the input and evaluate
XQueryEvaluator query = exec.load();
query.setContextItem(doc);
query.setExternalVariable(new QName("input"),doc.select(child("input")).asNode());
XdmValue result = query.evaluate();
System.out.println(result.itemAt(0).toString());
当我在Oxygen XML编辑器(使用Saxon-PE XQuery 9.9.1.7
引擎)中打开xquery时,无论使用Java代码,都会出现以下验证错误。
解决方法
这确实是Saxon优化错误。撒克逊人尝试重写时会发生问题
for $j in 1 to count($input/bar)
return if ($input/foo[$i]/data = 'A' and $input/baz[$i]/type = 'B')
then <result/>
else ()
为
if ($input/foo[$i]/data = 'A' and $input/baz[$i]/type = 'B')
then for $j in 1 to count($input/bar)
return <result/>
else ()
,您可以通过手工重写来解决此问题。重写的目的是为了防止不必要地重复评估“ if”条件,这种情况在循环中每次都相同。
之所以依赖于“和”条件,是因为撒克逊人将“和”的每个术语视为在循环之外晋升的单独候选者,并且当发现所有这些术语都可以被提升时,它将“和“”部分表达出来,而该错误是在重构过程中发生的。
,似乎是Saxon中的优化程序错误,我将您的代码缩减为
declare function local:test($input as element(input)) as element(output)
{
<output>
<details>
<service>
{
for $i in 1 to count($input/foo)
return
for $j in 1 to count($input/bar)
return if ($input/foo[$i]/data = 'A' and $input/baz[$i]/type = 'B')
then <result/>
else ()
}
</service>
</details>
</output>
};
declare variable $input as element(input) external := <input>
</input>;
local:test($input)
并且命令行中的Saxon HE 10.2崩溃
java.lang.NullPointerException
at net.sf.saxon.expr.parser.LoopLifter.markDependencies(LoopLifter.java:168)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:112)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:122)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:122)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:122)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:122)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:122)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:122)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:122)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:122)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:122)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:122)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:122)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:101)
at net.sf.saxon.expr.parser.LoopLifter.process(LoopLifter.java:51)
at net.sf.saxon.query.XQueryFunction.optimize(XQueryFunction.java:452)
at net.sf.saxon.query.XQueryFunctionLibrary.optimizeGlobalFunctions(XQueryFunctionLibrary.java:327)
at net.sf.saxon.query.QueryModule.optimizeGlobalFunctions(QueryModule.java:1207)
at net.sf.saxon.expr.instruct.Executable.fixupQueryModules(Executable.java:458)
at net.sf.saxon.query.XQueryParser.makeXQueryExpression(XQueryParser.java:177)
at net.sf.saxon.query.StaticQueryContext.compileQuery(StaticQueryContext.java:568)
at net.sf.saxon.query.StaticQueryContext.compileQuery(StaticQueryContext.java:630)
at net.sf.saxon.s9api.XQueryCompiler.compile(XQueryCompiler.java:609)
at net.sf.saxon.Query.compileQuery(Query.java:804)
at net.sf.saxon.Query.doQuery(Query.java:317)
at net.sf.saxon.Query.main(Query.java:97)
java.lang.NullPointerException
我认为您可以在命令行上使用-opt:0
关闭优化,这样上面的代码就不会崩溃。
您可能想在https://saxonica.plan.io/projects/saxon/issues上提出问题,或者等到Saxonica的某人在这里将其提起。
如果我使用
for $foo at $i in $input/foo
return
for $bar at $j in $input/bar
Saxon不会崩溃,因此也许这是一种重写查询的方法,尽管没有数据,但我不确定是否捕获了代码的含义,并且重写与原始代码相同尝试。
,我用马丁的测试用例(谢谢你,马丁)复制了它:https://saxonica.plan.io/issues/4765