我正在尝试使用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);
XPathContext
构造函数爆炸:
nu.xom.NamespaceConflictException:
XPath expressions do not use the default namespace
所以,我正在寻找:
更新:根据Lev Levitsky's answer和Jaxen FAQ,我提出了以下黑客行为:
XPathContext context = new XPathContext(
"foo",
document.getRootElement().getNamespaceURI());
Nodes divs = document.query("//foo:div");
这对我来说似乎有点疯狂,但我想这就是Jaxen希望你做事的方式。
更新#2:如下所述和all over the Internet,这不是Jaxen的错;它只是XPath是XPath。
所以,虽然这个hack有效,但我仍然想要一种去除命名空间声明的方法。最好不要走XSLT。
答案 0 :(得分:2)
你可以写:
Nodes divs = document.query("//*[local-name()='div' and namespace-uri()='http://www.w3.org/1999/xhtml']");
答案 1 :(得分:1)
您应该直接使用
之类的内容指定命名空间Nodes divs = document.query("//{http://www.w3.org/1999/xhtml}div");
或使用映射到各个名称空间的前缀(我猜这是NamespaceContext
的用途,但查询中没有前缀。)
不幸的是,我不知道它是如何在Java中实现的,但如果有帮助我可以提供一个Python示例。