带有lxml treebuilder的html5lib不能正确解析命名空间

时间:2012-09-03 20:41:43

标签: python lxml html5lib

我正在尝试使用html5lib treebuilder使用lxml解析一些HTML内容。注意:我正在使用requests库来获取内容,内容是HTML5(尝试使用XHTML - 结果相同)。

当我只输出HTML源代码时,它看起来没问题:

response = requests.get(url)
return response.text

返回

<html xmlns:foo="http://www.example.com/ns/foo">

但是当我实际用html5lib解析它时,会发生奇怪的事情:

tree = html5lib.parse(response.text, treebuilder = 'lxml', namespaceHTMLElements = True)
html = tree.getroot()
return lxml.etree.tostring(html, pretty_print = False)

返回

<html:html xmlns:html="http://www.w3.org/1999/xhtml" xmlnsU0003Afoo="http://www.example.com/ns/foo">

请注意xmlnsU0003Afoo事。

此外,html.nsmap dict不包含foo命名空间,仅包含html

有没有人知道发生了什么以及如何解决这个问题?

稍后编辑:

这似乎是预期的行为:

  

如果使用的XML API限制元素和属性的本地名称中的允许字符,则该工具可以将所有元素和属性本地名称[...]映射到一组允许的名称,通过替换任何大写字母U不支持的字符和字符的Unicode代码的六位数[...]    - Coercing an HTML DOM into an infoset

1 个答案:

答案 0 :(得分:2)

一些观察结果:

  • HTML5似乎不支持xmlns属性。引用section 1.6 of the latest HTML5 specification:“...命名空间无法使用HTML语法表示,但它们在DOM和XHTML语法中受支持。”我看到你也尝试过使用XHTML,但是你现在正在使用HTML5,因此可能存在问题。 U+003A是冒号的Unicode,所以xmlns不知何故被注意到了,但是不知所措。

  • 至少PHP版本有an open issue with custom namespace elements

  • 我不明白html5lib在这里的作用。为什么不直接使用lxml

from lxml import etree

tree = etree.fromstring(resp_text)
print etree.tostring(tree, pretty_print=True)

这似乎可以做到你想要的,没有html5lib而且没有愚蠢的xmlnsU0003Afoo错误。使用我使用的测试HTML,我得到了正确的输出(如下),tree.nsmap包含'foo'的条目。

<html xmlns:foo="http://www.example.com/ns/foo">
    <head>
        <title>yo</title>
    </head>
    <body>
        <p>test</p>
    </body>
</html>

或者,如果您希望使用纯html5lib,则可以使用附带的simpletree

tree = html5lib.parse(resp_text, namespaceHTMLElements=True)
print tree.toxml()

虽然这不会破坏xmlns属性,但遗憾的是simpletree缺少ElementTree功能更强大的xpath()功能。