我刚用nekohtml dom4j解析html文档时遇到了一些问题 .
我发现我的xpath表达式不再起作用,因为最近在html源上添加了一个新的默认html xml命名空间 .
规格说:
前缀xmlns仅用于声明名称空间绑定,并且根据定义绑定到名称空间名称http://www.w3.org/2000/xmlns/ . 它不能被宣布 . 其他前缀不得绑定到此命名空间名称,并且不得将其声明为默认命名空间 . 元素名称不能有前缀xmlns .
但在我的html文档中,最近(我猜)在html标签中添加了:xmlns =“http://www.w3.org/1999/xhtml”
我找到了2个解决方案
1)删除命名空间:
DOMParser parser = new DOMParser();
parser.setFeature("http://xml.org/sax/features/namespaces", false);
parser.parse(url);
根据NekoHTML faq的说法 .
2)为我的xpath添加一个前缀,绑定到默认的html命名空间 . (似乎它不能将前缀“空字符串”绑定到我想要的命名空间)
Map<String,String> XPATH_NAMESPACES = new HashMap<String, String>();
XPATH_NAMESPACES.put("my_prefix", "http://www.w3.org/1999/xhtml");
XPath xpath = document.createXPath(xpathExpr);
xpath.setNamespaceURIs(XPATH_NAMESPACES);
Element element = (Element) xpath.selectSingleNode(document);
然后,我使用// my_prefix:td而不是使用// td作为例子
我发布这些解决方案,因为有些人可能会发现这篇文章很有用 . 另见http://www.edankert.com/defaultnamespaces.html#Jaxen_and_Dom4J
但我真正想知道的是:
-
为什么要使用默认名称空间中的其他名称空间?
-
为什么有人会从http://www.w3.org/2000/xmlns/切换到http://www.w3.org/1999/xhtml?
-
为什么我们一般使用w3命名空间?命名空间是否会对浏览器产生一些影响?
我想我的问题对你们中的一些人来说似乎很明显,但我并没有真正意识到它带来了什么 . 我已经读过html和xhtml之间的区别 . 我想使用xhtml dtd的人宁愿使用这个命名空间,但除了它给爬行器或其他类似的东西带来一些额外的痛苦之外,还有什么真正的兴趣?
PS:我已经看到要从html传递到xhtml你必须添加xmlns和xml:lang,例如:所以它可能不是我解析的网站的目的,因为没有添加xml:lang ...
谢谢
2 回答
你误解了你所读到的内容 .
xmlns
属性的名称空间本身必须是http://www.w3.org/2000/xmlns/
. 默认命名空间(通过xmlns="something"
指定的命名空间可以,或者当然可以更改) .注意
是相同的
换句话说,默认命名空间只是一个方便的缩写,它允许您不为默认命名空间中的元素指定前缀 .
你的问题中存在很多混乱,如果不编写关于XML命名空间的完整教程,解决它并不容易 . 我将尽可能地覆盖它们与(X)HTML的关系 .
首先,命名空间的目的是分离词汇表 . 因此,例如,
http://www.w3.org/1999/xhtml
命名空间中的title
元素可以与http://www.w3.org/2000/svg
命名空间中的title
元素区分开来,当它们出现在同一文档中或由公共处理器处理时 .其次,忘记
http://www.w3.org/2000/xmlns/
命名空间 . 它的作用主要在幕后,你很少需要担心它 .接下来,我们需要区分null名称空间,默认名称空间和前缀引用的名称空间 .
当XML文件没有定义
xmlns=
属性时,所有未加前缀的元素都被认为是'in the null namespace'或'in no namespace',这相当于同一件事 .当XML元素具有
xmlns=
属性时,它及其后代元素(如果它们没有前缀)被称为'in the default namespace',其中默认命名空间是xmlns属性的值 .前缀元素始终位于由元素的元素或祖先中的
xmlns:prefix=
属性映射的命名空间中 .现在,XHTML词汇表被定义为
http://www.w3.org/1999/xhtml
命名空间中的元素,因此正确编写的XHTML文档将声明该命名空间作为默认命名空间,或者将前缀映射到命名空间,在这种情况下,所有XHTML元素都需要在他们的名字上加上那个前缀 . (由于下面给出的原因,后一种情况不会经常发生) .因此,在使用XML解析器解析XHTML时,名称空间映射需要存在 .
但是,XPath没有默认命名空间的概念 . 如果未将前缀放在xpath中指定的元素上,它将尝试匹配null命名空间中的元素 . 如果XHTML元素位于
http://www.w3.org/1999/xhtml
名称空间中,则xpath将不匹配任何内容 .这是它开始变得复杂的地方 - 浏览器 .
如果您按照自己的意愿向浏览器提供XHTML网页,使用XML内容类型(如application / xhtml xml),浏览器将使用XML解析器加载它,并应用上述所有规则 . 如果您不包含
xmlns="http://www.w3.org/1999/xhtml"
属性,浏览器将无法理解如何处理它,只会将文件显示为原始XML结构 .但是,因为IE直到IE9不支持XML内容类型,所以几乎没有人以这种方式提供网页 . 相反,他们使用“text / html”内容类型,在这种情况下,浏览器根本不使用XML解析器,它使用HTML .
HTML解析器就好了忽略命名空间以映射前缀,并简单地"knows"哪些元素名称属于哪些命名空间 . 这使得它最终不那么灵活,但在其专业领域内,更强大且易于使用 . (在上面的
title
元素的示例中,它通过查看title
的祖先元素来确定应用哪个命名空间)这就是为什么XHTML文档不能识别它们的原因 .浏览器(无论如何都是现代的),然后有专门的DOM类API方法和CSS规则来隐藏所有这些命名空间复杂性远离javascript和css作者,因此,在大多数情况下,网页作者可以安全地忽略命名空间 .
但是,独立的HTML解析器并不总是这样做 . 相反,它们将所有元素放在null命名空间中,这意味着可以使用标准DOM API找到不包含元素名称前缀的xpath . 对于大多数实际用途,这与浏览器使用HTML解析器进行解析时的情况相同 .
因此,总而言之,您需要了解您是使用XML还是HTML解析器解析XHTML,以及该特定解析器如何将元素分配给命名空间,以便能够编写正确的xpath来查询其中的元素该文件 .