lxml html5parser 忽略 "namespaceHTMLElements=False" 选项
lxml html5parser ignores "namespaceHTMLElements=False" option
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 接口的方式存在其他问题。
无论如何,我很想听听其他人是否有其他人 运行 遇到过这个问题并且有解决方法——或者至少对它发生的原因有一些了解。
我在 source-code 中关注了 lxml 如何将参数传递给 html5lib。大多数函数都有一个整理*kws,然后交给下一个函数。在调用实际 html5 解析器的最后步骤之一中,它被删除并使用 2 个固定参数调用解析器。
(我昨天也遇到了同样的问题,刚到这个问题,忘记了细节,请允许我放弃任何code-snippets和参考。)
无论如何,这证实了在 2018 年,直接调用 html5lib 仍然是首选方式,如果由于某种原因调用 lxml 自己的解析器不是一个选项。
(我的 use-case 是:解析糟糕的 html 并拥有 xpath。)
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 是实际上按预期使用
关于查找原因的结论
综上所述,很明显问题出在lxml和html5lib之间的接口上。我不确定为什么 lxml 两次调用 html5lib 但我认为这可能是因为出于某种原因它首先尝试创建自己的新实例 XHTMLParser
在做我实际要求它做的事情之前,这只是为了创建它自己的实例 HTMLParser
.
所以也许它确实对 html5lib 进行了两次调用这一事实导致 html5lib 有点“锁定”第一次调用产生的默认 namespaceHTMLElements=True
行为,然后忽略 namespaceHTMLElements=False
在第二次调用中看到它时的指令。
也许在以这种方式进行两次调用时,lxml 要么打破了 html5lib 中的某些假设,要么实际上以一种设计不打算使用的方式滥用 html5lib API。
或者根本不是 lxml 对 html5lib 进行两次单独调用的结果,而是它使用 html5lib 接口的方式存在其他问题。
无论如何,我很想听听其他人是否有其他人 运行 遇到过这个问题并且有解决方法——或者至少对它发生的原因有一些了解。
我在 source-code 中关注了 lxml 如何将参数传递给 html5lib。大多数函数都有一个整理*kws,然后交给下一个函数。在调用实际 html5 解析器的最后步骤之一中,它被删除并使用 2 个固定参数调用解析器。
(我昨天也遇到了同样的问题,刚到这个问题,忘记了细节,请允许我放弃任何code-snippets和参考。)
无论如何,这证实了在 2018 年,直接调用 html5lib 仍然是首选方式,如果由于某种原因调用 lxml 自己的解析器不是一个选项。
(我的 use-case 是:解析糟糕的 html 并拥有 xpath。)