Saxon xquery 验证失败 - 需要了解行为的帮助
Saxon xquery validation fails - help needed to understand behavior
虽然我正在使用 Saxon java api 来执行以下 xQuery,但我无法理解为什么以下执行/验证失败? (有趣的是,当我在 if 语句中用 or
替换 and
子句时,查询验证成功但我无法理解这种行为)
在 oxygen 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)
撒克逊版本
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 中的优化器错误,我将您的代码缩减为
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 不会崩溃,所以也许这是一种将查询重写为解决方法的方法,尽管没有数据,我不太确定我是否理解了代码的含义并且重写与你最初的尝试。
我用Martin的测试用例复现了(谢谢Martin):https://saxonica.plan.io/issues/4765
这确实是一个撒克逊优化错误。当 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”条件进行不必要的重复评估,每次循环都是相同的。
之所以依赖“and”条件,是因为Saxon把“and”的每一项都看作是单独提升到循环外的候选者,当它发现所有这些项都可以提升时,它就重新构造其部分的“和”表达式,错误发生在重构过程中。
虽然我正在使用 Saxon java api 来执行以下 xQuery,但我无法理解为什么以下执行/验证失败? (有趣的是,当我在 if 语句中用 or
替换 and
子句时,查询验证成功但我无法理解这种行为)
在 oxygen 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)
撒克逊版本
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 中的优化器错误,我将您的代码缩减为
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 不会崩溃,所以也许这是一种将查询重写为解决方法的方法,尽管没有数据,我不太确定我是否理解了代码的含义并且重写与你最初的尝试。
我用Martin的测试用例复现了(谢谢Martin):https://saxonica.plan.io/issues/4765
这确实是一个撒克逊优化错误。当 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”条件进行不必要的重复评估,每次循环都是相同的。
之所以依赖“and”条件,是因为Saxon把“and”的每一项都看作是单独提升到循环外的候选者,当它发现所有这些项都可以提升时,它就重新构造其部分的“和”表达式,错误发生在重构过程中。