如何对字符串中的XML运行XQuery?

Rob*_*ser 5 java xml xquery saxon

我有一些XML的String表示形式,并且我想在内存中对其运行XQuery。我一直在与Saxon一起玩,并提出了解决方案,但是为了使其正常工作,我做了一件丑陋的事情。我觉得这是因为我对撒克逊人缺乏经验。这是一些有效的代码:

import javax.xml.transform.URIResolver;
import net.sf.saxon.Configuration;
import net.sf.saxon.s9api.*;

public class XmlTest {
  public static void main(String[] args) {
    try {
      final String tableXml = 
        "<table>" + 
        "  <columns>" + 
        "    <column>Foo</column><column>Bar</column>" + 
        "  </columns>" + 
        "  <rows>" + 
        "    <row><cell>Foo1</cell><cell>Bar1</cell></row>" + 
        "    <row><cell>Foo2</cell><cell>Bar2</cell></row>" + 
        "  </rows>" + 
        "</table>";

      Configuration saxonConfig = new Configuration();
      Processor processor = new Processor(saxonConfig);

      XQueryCompiler xqueryCompiler = processor.newXQueryCompiler();
      XQueryExecutable xqueryExec = xqueryCompiler
              .compile("<result>{"
                       + "doc('')/table/rows/row/cell/text()='Foo2'"
                       + "}</result>");

      XQueryEvaluator xqueryEval = xqueryExec.load();
      xqueryEval.setSource(new SAXSource(new InputSource(
          new StringReader(tableXml))));

      XdmDestination destination = new XdmDestination();

      xqueryEval.setDestination(destination);

      // Avert your eyes!
      xqueryEval.setURIResolver(new URIResolver() {
        @Override
        public Source resolve(String href, String base) throws TransformerException {
            return new StreamSource(new StringReader(tableXml));
        }
      });

      xqueryEval.run();

      System.out.println(destination.getXdmNode());

    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我遇到的问题是XML文档的基本URI。由于它在内存中,因此没有可供参考的基本文档。我知道XML将始终是独立的,因此我决定重写URIResolverXML ,以便仅将包装在Source类型对象中的XML传回。我知道这是错误的,但是可以。如果我不这样做,则会出现Content not allowed in prolog错误。从错误消息的其余部分来看,它似乎正在尝试将当前目录读取为XML文件。这部分对我来说有点神秘,但我愿意学习!有正确的方法去做我想做的事吗?

Mic*_*Kay 4

如果您想使用 doc('') 访问源文档,那么可以这样做。但是,如果您编写查询来访问源文档作为上下文项的值,则会简单得多。所以你将查询更改为

"<result>{/table/rows/row/cell='Foo2'}</result>"
Run Code Online (Sandbox Code Playgroud)

您已经使用 setSource() 提供了上下文项,即使您没有使用它,因此这是您需要进行的唯一更改。

(我还从查询中删除了“/text()”,因为直接测试元素的值要好得多 - 这意味着如果源文档包含注释,您的查询仍然有效)。

  • 啊! 因此,对 URI 解析器的调用是因为引用了 `doc("")`。我最初编写的查询没有它,但添加它是为了尝试修复我遇到的错误(现在已忘记)。它留下来是因为我觉得它已经改善了事情,但现在我发现它是一个转移注意力的东西。如果没有对“doc()”的引用,我可以删除我的冒险 URIResolver 实现,并且一切正常。谢谢,迈克尔。 (2认同)