有办法强制lxml解析指定编码的Unicode字符串吗?
我有一个XML文件,它里面指定了一种编码方式。我用UnicodeDammit工具把它转换成Unicode格式(因为存储原因,我不能把它存成字符串)。后来我把这个文件传给lxml,但它不愿意忽略文件里指定的编码,还是按照原来的编码来解析,结果抛出了一个异常。
我该怎么做才能强制lxml解析这个文档呢?感觉它的这个行为太严格了。
4 个回答
解决方案并不是重新编码字符串。字符串内部的编码声明可能会是其他格式,而不仅仅是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),这其实挺糟糕的(但总比盲目编码成二进制要好),所以我欢迎大家提出建议。
附注:关于XML编码问题的一些有趣分析:
基本上,解决办法就是这样做:
if isinstance(mystring, unicode):
mystring = mystring.encode("utf-8")
说真的,lxml做得不错。
补充一下:在这个情况下,lxml错误地自动识别了编码。看起来我需要手动去查找并删除页面中的“charset”和“encoding”。
你不能同时从 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 编码。