lxml HTML5解析器忽略"namespaceHTMLElements=False"选项



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 html5解析器来尊重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规范的要求,包括必须将html元素放入HTML名称空间的要求——html5lib做到了这一点
  • 然而,html5lib提供了namespaceHTMLElements=False作为一个选项来覆盖默认的"将html元素放入HTML命名空间"行为。
  • 当我直接使用html5lib(不是通过lxml),并将namespaceHTMLElements=False传递给它时,一切都如预期的那样工作- html元素进入void命名空间。
  • 在html5lib源代码中插入一些printf,我观察到:

    • lxml 实际上是调用html5lib与namespaceHTMLElements=False如预期的
    • 但是, lxml似乎调用到html5lib 两次:第一次没有namespaceHTMLElements,然后第二次与namespaceHTMLElements=False

查找原因的结论

鉴于上述情况,很明显问题出在lxml和html5lib之间的接口上。我不知道为什么lxml调用到html5lib两次,但我认为这可能是因为出于某种原因,它首先尝试创建自己的XHTMLParser的新实例之前做什么我实际上要求它做,这只是创建自己的HTMLParser的实例。

因此,它确实对html5lib进行了两次调用,这可能导致html5lib在某种程度上"锁定"了第一次调用产生的默认namespaceHTMLElements=True行为,然后在第二次调用中看到namespaceHTMLElements=False指令时忽略它。

也许在进行两次调用的方式,lxml是打破了一些假设在html5lib,或实际上是误用html5lib API的方式,它的设计是不打算被使用。

或者原因根本不是lxml对html5lib进行两次单独调用的结果,而是它使用html5lib接口的方式出现了其他问题。

无论如何,我很想听听其他人是否遇到过这个问题并有解决办法,或者至少对为什么会发生这种情况有一些见解。

我在源代码中遵循了lxml如何将参数传递给html5lib。大多数函数都有一个结束*kws,然后将其传递给下一个函数。在调用实际的html5解析器的最后一个步骤中,这将被删除,解析器将使用2个固定参数调用。

(我昨天遇到了同样的问题,刚刚遇到这个问题,忘记了细节,请允许我放弃任何代码片段和引用。)

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

(我的用例是:解析蹩脚的html并使用xpath)

相关内容

  • 没有找到相关文章

最新更新