【问题标题】:Saxon xquery validation fails - help needed to understand behaviorSaxon xquery 验证失败 - 需要帮助来理解行为
【发布时间】:2021-01-14 18:18:17
【问题描述】:

虽然我使用 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)

撒克逊版本

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)的确切版本和版本,总是有帮助的。正如您所说,您编写 Java 代码以使用 Saxon,对该代码进行最少的复制也会有所帮助。
  • 已更新我的问题,提供更多详细信息@MartinHonnen!
  • 在 Java 代码中,您是否在 compiler.compile(new File(classLoader.getResource("Xquery.xqy").getFile())); 调用或稍后在 query.evaluate() 调用时收到错误?在后一种情况下,您还可以包含一个最小的 XML 示例吗?
  • 请澄清一下,您显示的代码 sn-p 使用or,屏幕截图and?两者都有问题吗?

标签: xquery saxon oxygenxml


【解决方案1】:

这确实是一个撒克逊优化错误。撒克逊人试图重写时会出现问题

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”的每个术语都视为循环外提升的单独候选,当它发现所有这些术语都可以提升时,它重新构成“ and" 从它的各个部分表达,并且在此重组过程中会发生错误。

【讨论】:

    【解决方案2】:

    这似乎是 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 不会崩溃,所以也许这是一种将您的查询重写为解决方法的方法,尽管没有数据,我不太确定我是否已经掌握了您的代码的含义,并且重写与您的原始代码相同尝试。

    【讨论】:

    • 谢谢马丁和@michael-kay,你的回答很有帮助!!到目前为止,我已将 if 子句拆分为单独的语句 if ($input/foo[$i]/data = 'A' and $input/baz[$i]/type = 'B')if ($input/foo[$i]/data = 'A') then if ($input/baz[$i]/type = 'B') 并得到了预期的结果。但是,我希望我们在不手动更改 xquery 的情况下获得预期的结果 :)
    【解决方案3】:

    我用 Martin 的测试用例复制了它(谢谢你,Martin):https://saxonica.plan.io/issues/4765

    【讨论】:

      猜你喜欢
      • 2014-06-20
      • 2016-04-28
      • 2011-03-25
      • 2015-09-16
      • 1970-01-01
      • 2011-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多