如何在 Java 中使用 Saxon XPath 2.0?

How to use Saxon XPath 2.0 with Java?

我喜欢在xPath中使用正则表达式,所以安装了Saxon9.6

  1. 我的 ${java.home} 是 C:\Program Files\Java\jdk1.7.0_51.
  2. 我在 C:\Program 中提取了 saxonHE9-6-0-6J.zip Files\Java\jdk1.7.0_51\jre\lib\ext
  3. 并将 saxonhe9.jar 添加到我的类路径变量中。
  4. 然后我在C:\Program下创建了一个jaxp.properties文件 Files\Java\jdk1.7.0_51\jre\lib 并添加以下行:

    javax.xml.transform.TransformerFactory = net.sf.saxon.TransformerFactoryImpl javax.xml.xpath.XPathFactory","net.sf.saxon.xpath.XPathFactoryImpl

但是现在我找不到像 this 页面上描述的例子。

(虽然这是目前公认的答案,但 中有一条重要信息,我认为这是对这个问题的更好答案,但是我无法更改已接受答案标志...)

使用 Saxon 在 Java 中设置转换非常容易,只需参考 the documentation here. Another straightforward how-to can be found here。其他例子遍布全网

XPath API for Java is documented here at Saxonica.

请注意,您的 link 引用的是 7.7 版。您下载了 9.6 版。如果您想使用 7.7 中的示例,您应该下载该版本。它们可能仍然有些准确,但我不确定。

在最新版本的 Saxon 中,JAR 文件不再包含将其宣传为 JAXP XPath 工厂提供程序的 meta-inf 服务文件。这是因为太多的应用程序有问题:如果应用程序被编写并测试为与 JDK 附带的 XPath 1.0 引擎一起工作,那么如果您尝试 运行,它很可能会失败它与 Saxon 的 XPath 2.0 引擎一起使用,而这仅仅是因为 Saxon 在 class 路径上。所以如果你想使用 Saxon 作为你的 XPath 引擎,你现在必须使请求明确,例如通过直接实例化 net.sf.saxon.xpath.XPathFactoryImpl

我的意思是调用 new XPathFactoryImpl() 而不是 XPathFactoryImpl.newInstance() 因为它继承自 XPathFactory

但是,由于 XPath 2.0 类型系统比 XPath 1.0 丰富得多,JAXP 界面确实很笨拙,我建议 using the s9api interface

使用 S9API 从未像它应该的那样简单。这是我可以创建的最简单的工作示例。这是一个完整的单元测试,适用于 NetBeans 8 中的 Saxon 9.7 HE。

假设这个 XML (simple.xml):

<person>
    <firstname>James</firstname>
    <age>25</age>
</person>

运行 这个单元测试,正在寻找名字节点:

import java.io.File;
import java.util.Iterator;
import java.util.List;
import javax.xml.transform.sax.SAXSource;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import javax.xml.xpath.XPathFactoryConfigurationException;
import net.sf.saxon.Configuration;
import net.sf.saxon.lib.NamespaceConstant;
import net.sf.saxon.om.DocumentInfo;
import net.sf.saxon.om.NodeInfo;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.xpath.XPathFactoryImpl;
import org.junit.Test;
import org.xml.sax.InputSource;
import static org.junit.Assert.*;

public class xPath2
{
    @Test
    public void mytest() throws XPathFactoryConfigurationException, XPathException, XPathExpressionException     
    {
        System.setProperty("javax.xml.xpath.XPathFactory:" + NamespaceConstant.OBJECT_MODEL_SAXON, "net.sf.saxon.xpath.XPathFactoryImpl");
        XPathFactory xPathFactory = XPathFactory.newInstance(NamespaceConstant.OBJECT_MODEL_SAXON);
        XPath xPath = xPathFactory.newXPath();
        InputSource inputSource = new InputSource(new File("simple.xml").toURI().toString());
        SAXSource saxSource = new SAXSource(inputSource);
        Configuration config = ((XPathFactoryImpl) xPathFactory).getConfiguration();
        DocumentInfo document = config.buildDocument(saxSource);      
        String xPathStatement = "//firstname";
        XPathExpression xPathExpression = xPath.compile(xPathStatement);  
        List matches = (List) xPathExpression.evaluate(document, XPathConstants.NODESET); 
        if (matches != null)
        {
            for (Iterator iter = matches.iterator(); iter.hasNext();)
            {
                NodeInfo node = (NodeInfo) iter.next();
                assertEquals("firstname", node.getDisplayName());
                assertEquals("James", node.getStringValue()); 
            }
        }
    }
}

这是 Saxon 9.7 资源 (http://www.saxonica.com/download/download_page.xml) 附带的示例之一的简化​​版本。

请注意,xPath 语句不是 xPath 2.0,但此代码可用于 2.0 语句。

我这样使用 Saxon-HE 9.8.0-5:

Processor processor = new Processor(false);
XdmNode xdm = processor.newDocumentBuilder().build(new StreamSource(new StringReader(xml)));
XdmValue result = processor.newXPathCompiler().evaluate(query, xdm);

StringBuilder sb = new StringBuilder();
for (int i = 0; i < result.size(); i++) {
    sb.append(result.itemAt(i).getStringValue());
    if (i + 1 != result.size()) {
        sb.append('\n');
    }
}