XPath:有没有办法为查询设置默认命名空间?

时间:2009-11-13 17:22:37

标签: java xpath

有没有办法将Java的XPath设置为表达式的默认名称空间前缀?例如,代替:/ html:html / html:head / html:title / text()“,查询可以是:/ html / head / title / text()

虽然使用名称空间前缀有效,但必须采用更优雅的方式。

我现在正在做的示例代码片段:

Node node = ... // DOM of a HTML document
XPath xpath = XPathFactory.newInstance().newXPath();

// set to a NamespaceContext that simply returns the prefix "html"
// and namespace URI ""http://www.w3.org/1999/xhtml"
xpath.setNamespaceContext(new HTMLNameSpace());

String expression = "/html:html/html:head/html:title/text()";
String value = xpath.evaluate(query, expression);

3 个答案:

答案 0 :(得分:10)

不幸的是,没有。几年前有一些关于为JxPath定义默认命名空间的讨论,但快速查看最新的文档并不表示发生了任何事情。不过,您可能希望花更多时间浏览文档。

如果你真的不关心命名空间,你可以做的一件事就是在没有它们的情况下解析文档。只需忽略您目前拨打DocumentBuilderFactory.setNamespaceAware()的电话。

另外,请注意您的前缀可以是您想要的任何内容;它不必匹配实例文档中的前缀。因此,您可以使用h而不是html,并最大限度地减少前缀的视觉混乱。

答案 1 :(得分:4)

我实际上没有尝试过这个,但是根据NamespaceContext文档,带有前缀“”(emtpy string)的名称空间上下文被认为是默认名称空间。


我对那个太快了。如果在XPath表达式“/ html / head / title / text()”中根本没有使用前缀,则XPath求值程序不会调用NamespaceContext来解析“”前缀。我现在要进入XML细节,我不是100%肯定,但使用像“/:html /:head /:title / text()”这样的表达式可以与Sun JDK 1.6.0_16一起使用,并且会询问NamespaceContext解析空前缀(“”)。这是非常正确和预期的行为还是Xalan中的错误?

答案 2 :(得分:2)

我知道这个问题已经过时了,但我花了3个小时研究试图解决这个问题,@kdgregorys answer帮我解决了很多问题。我只是想用kdgregorys答案作为指导,完全按照我的方式进行。

问题是,如果你的查询没有前缀,java中的XPath甚至不会查找命名空间,因此要将查询映射到特定的命名空间,你必须为查询添加前缀。我使用任意前缀映射到模式名称。对于此示例,我将使用OP的命名空间和查询以及前缀abc。你的新表达式如下所示:

String expression = "/abc:html/abc:head/abc:title/text()";

然后执行以下操作

1)确保您的文档设置为名称空间感知。

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);

2)实施将解析您的前缀的NamespaceContext。我从SO上的其他帖子中获取了这个并修改了一下

public class NamespaceResolver implements NamespaceContext {

    private final Document document;

    public NamespaceResolver(Document document) {
        this.document = document;
    }

    public String getNamespaceURI(String prefix) {
        if(prefix.equals("abc")) {
            // here is where you set your namespace
            return "http://www.w3.org/1999/xhtml";
        } else if (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) {
            return document.lookupNamespaceURI(null);
        } else {
            return document.lookupNamespaceURI(prefix);
        }
    }

    public String getPrefix(String namespaceURI) {
        return document.lookupPrefix(namespaceURI);
    }

    @SuppressWarnings("rawtypes")
    public Iterator getPrefixes(String namespaceURI) {
        // not implemented
        return null;
    }

}

3)创建XPath对象时设置NamespaceContext。

xPath.setNamespaceContext(new NamespaceResolver(document));

现在无论实际的模式前缀是什么,您都可以使用自己的前缀来映射到正确的模式。所以使用上面的类的完整代码看起来就像这样。

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);

Document document = factory.newDocumentBuilder().parse(sourceDocFile);

XPathFactory xPFactory = XPathFactory.newInstance();
XPath xPath = xPFactory.newXPath();
xPath.setNamespaceContext(new NamespaceResolver(document));

String expression = "/abc:html/abc:head/abc:title/text()";
String value = xpath.evaluate(query, expression);