2009-07-16 76 views
9

我用elementtree.parse()函数解析了一些XML。它的工作原理除了一些utf-8字符(128字节以上的单字节字符)。我看到默认的解析器是基于expat的XMLTreeBuilder。ElementTree替代XML解析器来缓解UTF-8的灾难?

有没有我可以使用,可能不太严格,并允许UTF-8字符替代分析器?

这是我与默认解析器得到的错误:

ExpatError: not well-formed (invalid token): line 311, column 190 

造成这种情况的字符是一个单字节X92(十六进制)。我不确定这甚至是一个有效的utf-8字符。但它会是不错的处理,因为大多数文本编辑器显示此为:我

编辑:人物的背景是:canít,在这里我想这应该是一个奇特的apostraphe,但在十六进制编辑器,则相同的序列为:63 61 6E 92 74

回答

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

字节0x92永远不会成为UTF-8字符的第一个字节的第一个字节。但是,它可以作为后续字节有效。有关有效字节序列的表,请参阅this UTF-8 guide

你能不能给我们带来什么字节周边0x92的想法? XML声明是否包含字符编码?

4

它看起来像你有CP1252文本。如果是的话,它应该在文件的顶部指定,如:

<?xml version="1.0" encoding="CP1252" ?> 

这确实与ElementTree的工作。

如果你自己创建这些文件,不要把它们写在这个编码。将它们保存为UTF-8,并尽你所能帮助杀死过时的文本编码。

如果您收到没有编码规范CP1252的数据,你肯定知道,它总是将是CP1252,你可以就其发送到解析器之前转换为UTF-8:

s.decode("CP1252").encode("UTF-8") 
+0

不是欧洲人,我们绝对是在美国。我没有这样做,我保证:) – Kekoa 2009-07-16 21:37:35

1

啊。这是“不可”,显然,在许多Windows代码页中0x92是一个撇号。你的编辑器会假设它是一个Mac文件。 ;)

如果它是一次性的,固定的文件是做正确的事。但是,当你需要导入其他人的XML时,几乎总是有很多事情不符合规定的编码。我发现最好的解决方案是使用错误设置'xmlcharrefreplace'进行解码,并且在严重情况下进行自定义字符替换,以修复该特定客户最常见的问题。

我也给你推荐LXML如在Python XML库,但在这里,这不是问题。