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”的每一项都看作是单独提升到循环外的候选者,当它发现所有这些项都可以提升时,它就重新构造其部分的“和”表达式,错误发生在重构过程中。