ElementTree的替代XML解析器,以缓解UTF-8的困境?

2024-04-16 14:27:44 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在用elementtree.parse()函数解析一些XML。它可以工作,除了一些utf-8字符(128以上的单字节字符)。我看到默认的解析器是基于expat的XMLTreeBuilder。

是否有一个替代的解析器,我可以使用它可能不那么严格,并允许utf-8字符?

这是我在使用默认解析器时遇到的错误:

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

导致这种情况的字符是单字节x92(十六进制)。我不确定这是不是一个有效的utf-8字符。但最好能处理它,因为大多数文本编辑器都将其显示为:

编辑:字符的上下文是:cant,这里我假设它是一个奇特的使徒,但是在十六进制编辑器中,相同的顺序是:63616e9274


Tags: 函数解析器parse错误notxml字符utf
3条回答

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

你能告诉我们0x92周围是什么字节吗?XML声明是否包含字符编码?

我将从这个问题开始:“是否有一个替代的解析器,我可以使用它可能不那么严格,并允许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

看起来你有CP1252文本。如果是,则应在文件顶部指定,例如:

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

这确实适用于ElementTree。

如果您自己创建这些文件,请不要用这种编码方式编写它们。将它们保存为UTF-8并尽自己的一份力量来帮助消除过时的文本编码。

如果您接收的是没有编码规范的CP1252数据,并且您确定它总是CP1252,那么您可以在将其发送到解析器之前将其转换为UTF-8:

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

相关问题 更多 >