问题 如何使用ElementTree正确解析utf-8 xml?


我需要帮助才能理解为什么要解析我的xml文件* xml.etree.ElementTree 产生以下错误。

*我的测试xml文件包含阿拉伯字符。 

任务: 打开并解析 utf8_file.xml 文件。

我的第一次尝试:

import xml.etree.ElementTree as etree
with codecs.open('utf8_file.xml', 'r', encoding='utf-8') as utf8_file:
    xml_tree = etree.parse(utf8_file)

结果1:

UnicodeEncodeError: 'ascii' codec can't encode characters in position 236-238: ordinal not in range(128)

我的第二次尝试:

import xml.etree.ElementTree as etree
with codecs.open('utf8_file.xml', 'r', encoding='utf-8') as utf8_file:
    xml_string = etree.tostring(utf8_file, encoding='utf-8', method='xml')
    xml_tree  = etree.fromstring(xml_string)

结果2:

AttributeError: 'file' object has no attribute 'getiterator'

请解释上面的错误并评论可能的解决方案。


7104
2018-02-11 09:36


起源



答案:


将字节解码到解析器;做  首先解码:

import xml.etree.ElementTree as etree
with open('utf8_file.xml', 'r') as xml_file:
    xml_tree = etree.parse(xml_file)

一个XML文件 必须 在第一行包含足够的信息来处理解析器的解码。如果缺少标头,则解析器必须假定使用UTF-8。

因为它是保存此信息的XML头,所以解析器负责进行所有解码。

您的第一次尝试失败,因为Python正在尝试 编码 再次使用Unicode值,以便解析器可以按预期处理字节字符串。第二次尝试失败是因为 etree.tostring() 期望解析的树作为第一个参数,而不是unicode字符串。


9
2018-02-11 09:41



很棒,它似乎比我想象的要容易。即使“没有BOM的utf-8”文件也能正确解析。 - minerals
没有BOM的UTF-8是标准; 同 BOM主要是微软希望能够更容易地自动检测除UTF-8之外的8位编码。 - Martijn Pieters♦
etree.parse(a_file) 默认情况下处理Unicode。然而 etree.fromstring(a_string) 直到Python 3.x(见 bugs.python.org/issue11033所以要解析一个字符串,你必须手动编码,比如 etree.fromstring(a_string.encode('utf-8'))。 - Chris Johnson
@ChrisJohnson:这个问题是关于Python 2的,其中文件对象产生字节字符串,而不是Unicode。问题涉及用户从文件中读取数据并手动解码,这完全没有意义。 - Martijn Pieters♦
@MartijnPieters我同意。此评论旨在为任何研究基于字符串的方法的人指出一个非显而易见的行为。基于文件的方法默认处理编码是不明显的,但基于字符串的方法需要预编码。 - Chris Johnson


答案:


将字节解码到解析器;做  首先解码:

import xml.etree.ElementTree as etree
with open('utf8_file.xml', 'r') as xml_file:
    xml_tree = etree.parse(xml_file)

一个XML文件 必须 在第一行包含足够的信息来处理解析器的解码。如果缺少标头,则解析器必须假定使用UTF-8。

因为它是保存此信息的XML头,所以解析器负责进行所有解码。

您的第一次尝试失败,因为Python正在尝试 编码 再次使用Unicode值,以便解析器可以按预期处理字节字符串。第二次尝试失败是因为 etree.tostring() 期望解析的树作为第一个参数,而不是unicode字符串。


9
2018-02-11 09:41



很棒,它似乎比我想象的要容易。即使“没有BOM的utf-8”文件也能正确解析。 - minerals
没有BOM的UTF-8是标准; 同 BOM主要是微软希望能够更容易地自动检测除UTF-8之外的8位编码。 - Martijn Pieters♦
etree.parse(a_file) 默认情况下处理Unicode。然而 etree.fromstring(a_string) 直到Python 3.x(见 bugs.python.org/issue11033所以要解析一个字符串,你必须手动编码,比如 etree.fromstring(a_string.encode('utf-8'))。 - Chris Johnson
@ChrisJohnson:这个问题是关于Python 2的,其中文件对象产生字节字符串,而不是Unicode。问题涉及用户从文件中读取数据并手动解码,这完全没有意义。 - Martijn Pieters♦
@MartijnPieters我同意。此评论旨在为任何研究基于字符串的方法的人指出一个非显而易见的行为。基于文件的方法默认处理编码是不明显的,但基于字符串的方法需要预编码。 - Chris Johnson