有没有办法强制lxml解析指定标记中编码的Unicode字符串?

时间:2010-08-04 04:13:11

标签: python lxml

我有一个指定编码的XML文件,我使用UnicodeDammit将其转换为unicode(出于存储原因,我无法将其存储为字符串)。我稍后将它传递给lxml,但它拒绝忽略文件中指定的编码并将其解析为Unicode,并引发异常。

如何强制lxml解析文档?这种行为似乎过于严格。

4 个答案:

答案 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()