我正在使用elementtree.parse()函数解析一些XML。它工作,除了一些utf-8字符(128字节以上的单字节字符)。我看到默认的解析器是XMLTreeBuilder,它基于expat。
我可以使用的替代解析器可能不那么严格并且允许使用utf-8字符吗?
这是我使用默认解析器得到的错误:
ExpatError: not well-formed (invalid token): line 311, column 190
导致此字符的字符是单字节x92(十六进制)。我不确定这甚至是一个有效的utf-8字符。但处理它会很好,因为大多数文本编辑器将其显示为:í
编辑:角色的上下文是:canít,我认为它应该是一个花哨的撇号,但在十六进制编辑器中,相同的序列是:63 61 6E 92 74 < / p>
答案 0 :(得分:15)
我将从问题开始:“我可以使用的替代解析器可能不那么严格并允许使用utf-8字符吗?”
所有XML解析器都将接受以UTF-8编码的数据。实际上,UTF-8是默认编码。
XML文档可以从这样的声明开始:
`<?xml version="1.0" encoding="UTF-8"?>`
或者像这样:
<?xml version="1.0"?>
或根本没有声明...在每种情况下,解析器将使用UTF-8解码文档。
但是你的数据不是用UTF-8编码的......它可能是Windows-1252,也就是cp1252。
如果编码不是UTF-8,则创建者应该包含声明(或者收件人可以添加一个声明),或者收件人可以将数据转码为UTF-8。以下展示了哪些有效,哪些无效:
>>> import xml.etree.ElementTree as ET
>>> from StringIO import StringIO as sio
>>> raw_text = '<root>can\x92t</root>' # text encoded in cp1252, no XML declaration
>>> t = ET.parse(sio(raw_text))
[tracebacks omitted]
xml.parsers.expat.ExpatError: not well-formed (invalid token): line 1, column 9
# parser is expecting UTF-8
>>> t = ET.parse(sio('<?xml version="1.0" encoding="UTF-8"?>' + raw_text))
xml.parsers.expat.ExpatError: not well-formed (invalid token): line 1, column 47
# parser is expecting UTF-8 again
>>> t = ET.parse(sio('<?xml version="1.0" encoding="cp1252"?>' + raw_text))
>>> t.getroot().text
u'can\u2019t'
# parser was told to expect cp1252; it works
>>> import unicodedata
>>> unicodedata.name(u'\u2019')
'RIGHT SINGLE QUOTATION MARK'
# not quite an apostrophe, but better than an exception
>>> fixed_text = raw_text.decode('cp1252').encode('utf8')
# alternative: we transcode the data to UTF-8
>>> t = ET.parse(sio(fixed_text))
>>> t.getroot().text
u'can\u2019t'
# UTF-8 is the default; no declaration needed
答案 1 :(得分:4)
看起来你有CP1252文字。如果是,则应在文件顶部指定,例如:
<?xml version="1.0" encoding="CP1252" ?>
这适用于ElementTree。
如果您自己创建这些文件,请不要使用此编码进行编写。将它们保存为UTF-8并尽力帮助杀死过时的文本编码。
如果您正在接收没有编码规范的CP1252数据,并且您确定它始终是CP1252,您可以在将其发送到解析器之前将其转换为UTF-8:
s.decode("CP1252").encode("UTF-8")
答案 2 :(得分:1)
字节0x92永远不会作为UTF-8字符的第一个字节有效。但是,它可以作为后续字节有效。有关有效字节序列的表,请参见this UTF-8 guide。
你能告诉我们0x92周围的字节是什么吗? XML声明是否包含字符编码?
答案 3 :(得分:1)
阿。显然,这是“不可能”,事实上,在许多Windows代码页中,0x92是一个撇号。您的编辑器假设它是一个Mac文件。 ;)
如果是一次性的,修复文件是正确的做法。但几乎总是当你需要导入其他人的XML时,有很多东西根本不同意所述的编码。我发现最好的解决方案是使用错误设置'xmlcharrefreplace'进行解码,并且在严重的情况下执行您自己的自定义字符替换,以修复该特定客户的最常见问题。
我还会在Python中推荐lxml作为XML库,但这不是问题所在。