读取UTF-8 XML并使用Python将其写入文件

时间:2010-06-10 05:52:07

标签: python xml utf-8

我正在尝试解析UTF-8 XML文件并将其中的一些部分保存到另一个文件中。问题是,这是我的第一个Python脚本,我对我找到的字符编码问题感到困惑。

我的脚本在尝试将非ascii字符写入文件时立即失败,但它可以将其打印到命令提示符(至少在某种程度上)

这是XML(来自至少重要的部分,它是包含UI字符串的* .resx文件)

<?xml version="1.0" encoding="utf-8"?>
<root>
     <resheader name="foo">
          <value>bar</value>
     </resheader>
     <data name="lorem" xml:space="preserve">
          <value>ipsum öä</value>
     </data>
</root>

这是我的python脚本

from xml.dom.minidom import parse

names = []
values = []

def getStrings(path):
    dom = parse(path)
    data = dom.getElementsByTagName("data")

    for i in range(len(data)):
        name = data[i].getAttribute("name")
        names.append(name)
        value = data[i].getElementsByTagName("value")
        values.append(value[0].firstChild.nodeValue.encode("utf-8"))

def writeToFile():
    with open("uiStrings-fi.py", "w") as f:
        for i in range(len(names)):
            line = names[i] + '="'+ values[i] + '"' #varName='varValue'
            f.write(line)
            f.write("\n")

getStrings("ResourceFile.fi-FI.resx")
writeToFile()

这是追溯:

Traceback (most recent call last):
  File "GenerateLanguageFiles.py", line 24, in 
    writeToFile()
  File "GenerateLanguageFiles.py", line 19, in writeToFile
    line = names[i] + '="'+ values[i] + '"' #varName='varValue'
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 2: ordinal not in ran
ge(128)

我应该如何修复脚本以便正确读写UTF-8字符?我正在尝试生成的文件将用于机器人框架的测试自动化。

2 个答案:

答案 0 :(得分:7)

您需要移除对encode()的调用 - 也就是说,将nodeValue.encode("utf-8")替换为nodeValue - 然后将调用更改为open()

with open("uiStrings-fi.py", "w", "utf-8") as f:

这使用了open()的“Unicode-aware”版本,您需要从codecs模块导入,因此还要添加

from codecs import open

到文件的顶部。

问题在于,当您调用nodeValue.encode("utf-8")时,您将Unicode字符串(Python的内部表示形式,可以存储所有Unicode字符)转换为常规字符串(只能存储单字节字符0-255) )。稍后,当您构造要写入输出文件的行时,names[i]仍然是Unicode字符串,但values[i]是常规字符串。 Python尝试将常规字符串转换为Unicode,这是更通用的类型,但由于您没有指定显式转换,它使用ASCII编解码器,这是默认值,而ASCII无法处理字节值更大的字符不幸的是,其中一些确实出现在字符串values[i]中,因为UTF-8编码经常使用那些高范围字节。所以Python抱怨说它看到了一个无法处理的角色。正如我上面所说,解决方案是将转换从Unicode推迟到字节,直到最后一刻,你可以使用支持Unicode的版本open(它将为你处理编码)。

现在我考虑一下,而不是我上面所说的,另一种解决方案是用names[i]替换names[i].encode("utf-8")。这样,您也可以将names[i]转换为常规字符串,而Python没有理由尝试将values[i]转换回Unicode。虽然,人们可以认为将字符串保存为Unicode对象是好的做法,直到将它们写入文件为止......如果没有别的,我相信unicode成为Python 3中的默认值。

答案 1 :(得分:0)

XML解析器在读取文件时解码输入的UTF-8编码,然后生成的DOM的所有文本节点和属性都是unicode对象。当您从DOM中选择有趣的数据时,将values重新编码为UTF-8,但不对names进行编码。生成的values数组包含编码的字节字符串,而names数组仍包含unicode对象。

在抛出编码错误的行中,Python尝试连接这样的unicode名称和字节字符串值。为此,两个值必须是相同的类型,Python尝试将字节字符串values[i]转换为unicode,但它不知道它是UTF-8编码并且在尝试使用ASCII时失败编解码器。

解决此问题的最简单方法是将所有字符串保留为Unicode对象,并在将它们写入文件时将其编码为UTF-8:

values.append(value[0].firstChild.nodeValue) # encode not yet
...
f.write(line.encode('utf-8')) # but now