lxml html5parser忽略" namespaceHTMLElements = False"选项

时间:2015-09-23 05:16:51

标签: html html5 html-parsing lxml html5lib

lxml html5parser似乎忽略了我传递给它的任何namespaceHTMLElements=False选项。它将我提供的所有元素放入HTML命名空间而不是(预期的)void命名空间。

这是一个简单的案例,可以重现问题:

echo "<p>" | python -c "from sys import stdin; \
  from lxml.html import html5parser as h5, tostring; \
  print tostring(h5.parse(stdin, h5.HTMLParser(namespaceHTMLElements=False)))"

这个的输出是这样的:

<html:html xmlns:html="http://www.w3.org/1999/xhtml"><html:head></html:head><html:body><html:p>
</html:p></html:body></html:html>

可以看出,html元素和HTML名称空间中的所有其他元素。

预期的输出是:

<html><head></head><body><p>
</p></body></html>

我认识到namespaceHTMLElements是一个html5lib选项,而不是lxml直接执行任何操作的本机lxml选项。 lxml应该只调用html5lib并将该选项传递给html5lib,以便html5lib按预期使用它。

更新2016-02-17

我仍然没有办法让lxml html5parser兑现namespaceHTMLElements。但要明确的是,另一种方法是直接调用html5lib,如下所示:

echo "<p>" | python -c "from sys import stdin; \
import html5lib; from lxml import html; \
doc = html5lib.parse(stdin, treebuilder='lxml', namespaceHTMLElements=False); \
print html.tostring(doc)"

更多详情

我已经知道的一些事情:

  • html5lib完全符合HTML规范的要求,包括the requirement that the html element must be placed into the HTML namespace - html5lib所做的
  • 但是,html5lib提供namespaceHTMLElements=False作为选项来覆盖默认的“将html元素放入HTML命名空间”行为。
  • 当我直接使用html5lib(而不是通过lxml),并且我将namespaceHTMLElements=False传递给它时,一切都按预期工作 - html元素进入void命名空间。
  • 将一些printf攻击到html5lib源代码中,我观察到:

    • lxml 实际上正在按照预期namespaceHTMLElements=False调用html5lib
    • 但是,lxml似乎是在调用html5lib 两次:首先是namespaceHTMLElements,然后是第二次namespaceHTMLElements=False

关于找到原因的结论

鉴于上述情况,很明显问题出在lxml和html5lib之间的界面中。我不确定为什么lxml会两次调用html5lib,但我认为这可能是因为出于某种原因它首先尝试创建自己的XHTMLParser的新实例,然后再做我实际要求它做的事情,这只是为了创建自己的HTMLParser

的实例

因此,它可能会对html5lib进行两次调用,导致html5lib排序“锁定”第一次调用产生的默认namespaceHTMLElements=True行为,然后忽略namespaceHTMLElements=False指令它在第二次通话中看到它。

也许按照它的方式进行两次调用,lxml要么在html5lib中打破一些假设,要么实际上误用了html5lib API,而不是设计使用它。

或许原因根本不是lxml对html5lib进行两次单独调用的结果,而是使用html5lib接口的方式中的其他一些问题。

无论如何,我有兴趣听别人说是否有其他人遇到过这个问题而且有一个解决方法 - 或者至少对它为什么会发生这种情况有所了解。

1 个答案:

答案 0 :(得分:0)

我已经在源代码中跟随了lxml如何将params移植到html5lib。大多数函数都有一个整理* kws,然后交给下一个函数。在调用实际的html5解析器的最后一步中,将其删除,并使用2个固定参数调用解析器。

(昨天我遇到了同样的问题,只是解决了这个问题,忘记了细节,允许我放弃任何代码片段和参考资料。)

无论如何,这证实了在2018年,直接调用html5lib仍然是首选方法,如果由于某种原因调用lxml自己的解析器不是一个选项。

(我的用例是:解析蹩脚的HTML并拥有xpath。)