我正在尝试使用 XOM 解析外部系统返回的一些 HTML。 HTML 看起来像这样:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<body>
<div>
Help I am trapped in a fortune cookie factory
</div>
</body>
</html>
(实际上它更加混乱,但它有这个 DOCTYPE 声明以及这些命名空间和语言声明,并且上面的 HTML 表现出与真正的 HTML 相同的问题。)
我想做的是提取内容<div>
,但是命名空间声明似乎使 XPath 感到困惑。如果我(从文件中手动)删除名称空间声明,以下代码会找到<div>
, 没问题:
Document document = ...
Nodes divs = document.query("//div");
但是有了命名空间,返回的Nodes
大小为 0。
好吧,如果我以编程方式剥离命名空间怎么样?
Element rootElement = document.getRootElement();
rootElement.removeNamespaceDeclaration(rootElement.getNamespacePrefix());
...看起来应该有效,但什么也没做。来自javadoc:
此方法仅删除添加的附加命名空间addNamespaceDeclaration.
好吧,我想,我将为查询提供名称空间:
XPathContext context =
XPathContext.makeNamespaceContext(document.getRootElement());
Nodes divs = document.query("//div", context);
大小仍然为零。
手动构建命名空间上下文怎么样?
XPathContext context = context = new XPathContext(
rootElement.getNamespacePrefix(), rootElement.getNamespaceURI());
Nodes divs = document.query("//div", context);
The XPathContext
构造函数爆炸:
nu.xom.NamespaceConflictException:
XPath expressions do not use the default namespace
所以,我正在寻找:
- 一种使该查询工作的方法,或者
- 一种以编程方式剥离命名空间声明的方法,或者
- 假设这两种方法都是错误的,则解释正确的方法。
Update:基于列夫·列维茨基的回答和贾克森常见问题解答我想出了以下技巧:
XPathContext context = new XPathContext(
"foo",
document.getRootElement().getNamespaceURI());
Nodes divs = document.query("//foo:div");
我觉得这仍然有点疯狂,但我想这就是贾克森希望你做事的方式。
更新#2:如下所述和整个互联网,这不是贾克森的错; XPath 就是 XPath。
因此,虽然这个 hack 有效,但我仍然想要一种删除名称空间声明的方法。最好不要使用 XSLT。