【发布时间】:2010-08-04 04:13:10
【问题描述】:
我有一个指定编码的 XML 文件,我使用 UnicodeDammit 将其转换为 unicode(出于存储原因,我不能将其存储为字符串)。我后来将它传递给 lxml 但它拒绝忽略文件中指定的编码并将其解析为 Unicode,并引发异常。
如何强制 lxml 解析文档?这种行为似乎过于严格。
【问题讨论】:
我有一个指定编码的 XML 文件,我使用 UnicodeDammit 将其转换为 unicode(出于存储原因,我不能将其存储为字符串)。我后来将它传递给 lxml 但它拒绝忽略文件中指定的编码并将其解析为 Unicode,并引发异常。
如何强制 lxml 解析文档?这种行为似乎过于严格。
【问题讨论】:
您不能从 unicode 字符串解析并且在字符串中有编码声明。
所以,要么你把它变成一个编码字符串(因为你显然不能将它存储为一个字符串,你必须在解析之前重新编码它。或者你自己用 lxml 将树序列化为 unicode:etree.tostring(tree, encoding=unicode),没有 xml声明。你可以很容易地用 etree.fromunicode 再次解析结果
见http://lxml.de/parsing.html#python-unicode-strings
编辑:显然,如果您已经拥有 unicode 字符串,并且无法控制它是如何制作的。您必须再次对其进行编码,并向解析器提供您使用的编码:
utf8_parser = etree.XMLParser(encoding='utf-8')
def parse_from_unicode(unicode_str):
s = unicode_str.encode('utf-8')
return etree.fromstring(s, parser=utf8_parser)
这将确保忽略 xml 声明中的任何内容,因为解析器将始终使用 utf-8。
【讨论】:
基本上,解决办法是:
if isinstance(mystring, unicode):
mystring = mystring.encode("utf-8")
说真的。干得好,lxml。
编辑:事实证明,在这种情况下,lxml 自动检测编码不正确。看来我将不得不从页面中手动搜索并删除“charset”和“encoding”。
【讨论】:
解决方案不是重新编码字符串。字符串中的编码声明可以表示 UTF8 以外的内容。不要盲目地重新编码为 utf8 并期望它能一直工作。
解决方案是去掉编码声明。你手头已经有一个 unicode 字符串,不再需要它了!
# this is from lxml/apihelpers.pxi
RE_XML_ENCODING = re.compile(
ur'^(<\?xml[^>]+)\s+encoding\s*=\s*["\'][^"\']*["\'](\s*\?>|)', re.U)
RE_XML_ENCODING.sub("", broken_xml_string, count=1)
这里最坏的情况(没有找到 xml 编码声明)时间复杂度是 O(n),这非常糟糕(但仍然比盲目编码为二进制更好),所以我愿意接受这里的建议。
PS:xml编码问题的一些有趣分析:
default encoding for XML is UTF-8 or UTF-16?
How default is the default encoding (UTF-8) in the XML Declaration?
【讨论】:
我有一个现有的实现,我需要树。 我也有一个 nbsp;元标记中的问题。将 resolve_entities 设置为 false 可以解决该问题。
opener = urllib.request.build_opener()
response = opener.open(url['url'])
raw_page = response.read()
response.close()
parsed_page = raw_page.replace(b'encoding="UTF-8"',b'')
parsed_page = StringIO(parsed_page.decode('ASCII'))
parser = ET.XMLParser(resolve_entities = False, encoding="ASCII")
tree = ET.parse(parsed_page, parser)
root = tree.getroot()
【讨论】: