我有一个指定编码的XML文件,我使用UnicodeDammit将其转换为unicode(出于存储原因,我无法将其存储为字符串)。我稍后将它传递给lxml,但它拒绝忽略文件中指定的编码并将其解析为Unicode,并引发异常。
如何强制lxml解析文档?这种行为似乎过于严格。
答案 0 :(得分:18)
您无法从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。
答案 1 :(得分:4)
基本上,解决方案是:
if isinstance(mystring, unicode):
mystring = mystring.encode("utf-8")
严重。干得好,lxml。
编辑:事实证明,在这种情况下,lxml 错误地自动检测编码。我似乎必须手动搜索并从页面中删除“charset”和“encoding”。
答案 2 :(得分:1)
解决方案不是重新编码字符串。字符串中的编码声明可以说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?
答案 3 :(得分:0)
我有一个现有的实现,我需要有这棵树。 我也有一个 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()