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 直接用它自己做任何事情的 native 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 之间的接口(interface)上。我不确定为什么 lxml 两次调用 html5lib,但我认为这可能是因为出于某种原因,它首先尝试创建自己的 XHTMLParser 的新实例,然后再执行我实际要求它执行的操作,这只是为了创建自己的 HTMLParser 实例。

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

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

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

    无论如何,我很想听听其他人是否遇到过这个问题并有解决方法——或者至少对它发生的原因有一些了解。

    最佳答案

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

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

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

    (我的用例是:解析糟糕的 html 并使用 xpath。)

    关于html - lxml html5parser 忽略 "namespaceHTMLElements=False"选项,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32731479/

    10-11 11:50