Html,xmlns,命名空间,xml

时间:2011-04-18 21:53:39

标签: html xml namespaces xml-namespaces

我在使用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);

然后,不使用// td作为例子,而是使用// my_prefix:td

我发布这些解决方案,因为有些人可能会觉得这篇文章很有用。 另请参阅http://www.edankert.com/defaultnamespaces.html#Jaxen_and_Dom4J

但我真正想知道的是:

我想我的问题对你们这些人来说似乎很明显,但我并没有真正理解它带来的东西。 我已经读过html和xhtml之间的区别。我想使用xhtml dtd的人宁愿使用这个命名空间,但除了它给爬虫或其他类似的东西带来额外的痛苦之外,还有什么真正的兴趣呢?

PS:我已经看到要从html传递到xhtml,你必须添加xmlns和xml:lang,例如: 所以它可能不是我解析的网站的目的,因为没有添加xml:lang ......

由于

2 个答案:

答案 0 :(得分:10)

你的问题中存在很多混淆,如果不编写关于XML命名空间的完整教程,解决它并不容易。我将尽可能地覆盖它们与(X)HTML的关系。

首先,命名空间的目的是分离词汇表。因此,例如,title命名空间中的http://www.w3.org/1999/xhtml元素可以与title命名空间中的http://www.w3.org/2000/svg元素区分开来,当它们出现在同一文档中或处理时由一个共同的处理器。

其次,忘记http://www.w3.org/2000/xmlns/命名空间。它的作用主要在幕后,你很少需要担心它。

接下来,我们需要区分null名称空间,默认名称空间和前缀引用的名称空间。

当XML文件没有定义xmlns=个属性时,所有未加前缀的元素都被称为“在null名称空间中”或“在没有名称空间”中,这相当于同样的事情。

当XML元素具有xmlns=属性时,它及其后代元素(如果它们没有前缀)被称为“在默认命名空间中”,其中默认命名空间是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解析器只是忽略命名空间来为映射添加前缀,而只是“知道”哪些元素名称属于哪些命名空间。这使得它最终不那么灵活,但在其专业领域内,更强大且易于使用。 (在上面的title元素的示例中,它通过查看title s祖先元素来确定应用哪个命名空间。这就是为什么XHTML文档不使用前缀元素,因为HTML解析器赢了'认识他们。

浏览器(无论如何都是现代的),然后有专门的DOM类API方法和CSS规则来隐藏所有这些命名空间复杂性远离javascript和css作者,因此,在大多数情况下,命名空间可以安全地被忽略网络作者。

但是,独立的HTML解析器并不总是这样做。相反,它们将所有元素放在null命名空间中,这意味着可以使用标准DOM API找到在元素名称上不包含前缀的xpath。对于大多数实际用途,这与浏览器使用HTML解析器进行解析时的情况相同。

因此,总而言之,您需要了解您是使用XML还是HTML解析器解析XHTML,以及该特定解析器如何将元素分配给命名空间,以便能够编写正确的xpath进行查询对于文档中的元素。

答案 1 :(得分:1)

你误解了你所读到的内容。 xmlns属性本身的名称空间必须为http://www.w3.org/2000/xmlns/xmlns="something"指定的名称空间可以更改。

请注意

<element1 xmlns="something">
    <element2/>
</element1>

相同
<x:element1 xmlns:x="something">
    <x:element2/>
</x:element1>

换句话说,默认命名空间只是一个方便的缩写,它允许您不为默认命名空间中的元素指定前缀。