使用lxml处理XML文档中的实体的最佳方法是什么?

时间:2011-03-02 16:14:38

标签: python lxml

请考虑以下事项:

from lxml import etree
from StringIO import StringIO

x = """<?xml version="1.0" encoding="utf-8"?>\n<aa>&nbsp;&acirc;</aa>"""
p = etree.XMLParser(remove_blank_text=True, resolve_entities=False)
r = etree.parse(StringIO(x), p)

这会失败:
lxml.etree.XMLSyntaxError: Entity 'nbsp' not defined, line 2, column 11

这是因为resolve_entities=False不会忽略它们,它只是不解决它们。

如果我改为使用etree.HTMLParser,则会创建htmlbody标记,以及它为HTML尝试执行的许多其他特殊处理。

使用lxml在&nbsp;&acirc;标记下获取aa文本子项的最佳方法是什么?

3 个答案:

答案 0 :(得分:12)

您不能忽略实体,因为它们是XML定义的一部分。如果您的文档没有DTD或独立=“是”,或者它包含DTD中没有实体定义的实体,则文档格式不正确。谎言并声称您的文档是HTML。

https://mailman-mail5.webfaction.com/pipermail/lxml/2008-February/003398.html

您可以尝试撒谎并在文档上放置XHTML DTD。 e.g。

from lxml import etree
try:
    from StringIO import StringIO
except ImportError:
    from io import StringIO
x = """<?xml version="1.0" encoding="utf-8"?>\n<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >\n<aa>&nbsp;&acirc;</aa>"""
p = etree.XMLParser(remove_blank_text=True, resolve_entities=False)
r = etree.parse(StringIO(x), p)
etree.tostring(r) # '<aa>&nbsp;&acirc;</aa>'

答案 1 :(得分:6)

@Alex是对的:您的文档格式不是格式良好的XML,因此XML解析器不会对其进行解析。一种选择是预处理文档的文本,用utf-8字符替换虚假实体:

entities = [
    ('&nbsp;', u'\u00a0'),
    ('&acirc;', u'\u00e2'),
    ...
    ]

for before, after in entities:
    x = x.replace(before, after.encode('utf8'))

当然,这也可以通过足够奇怪的“xml”打破。

最好的办法是将输入的XML文档修复为格式良好的XML。

答案 2 :(得分:-2)

当我尝试做类似的事情时,我在解析字符串之前只使用了x.replace('&', '&amp;')