有没有办法将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);
答案 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);