【问题标题】:Reading UTF-8 XML and writing it to a file with Python读取 UTF-8 XML 并使用 Python 将其写入文件
【发布时间】:2011-03-02 00:21:37
【问题描述】:

我正在尝试解析 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()

这是回溯:

回溯(最近一次通话最后): 文件“GenerateLanguageFiles.py”,第 24 行,在 写入文件() 文件“GenerateLanguageFiles.py”,第 19 行,在 writeToFile 行 = 名称[i] + '="'+ 值[i] + '"' #varName='varValue' UnicodeDecodeError:“ascii”编解码器无法解码位置 2 中的字节 0xc3:序数不在运行中 葛(128)

我应该如何修复我的脚本,以便它可以正确读取和写入 UTF-8 字符?我尝试生成的文件将用于 Robots Framework 的测试自动化。

【问题讨论】:

    标签: python xml utf-8


    【解决方案1】:

    您需要删除对encode() 的调用——即将nodeValue.encode("utf-8") 替换为nodeValue——然后将对open() 的调用更改为

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

    这使用open() 的“Unicode 感知”版本,您需要从codecs 模块导入它,所以还要添加

    from codecs import open
    

    到文件的顶部。

    问题在于,当您调用nodeValue.encode("utf-8") 时,您正在将 Unicode 字符串(可以存储所有 Unicode 字符的 Python 内部表示)转换为常规字符串(只能存储单字节字符 0-255)。稍后,当您构造要写入输出文件的行时,names[i] 仍然是 Unicode 字符串,但 values[i] 是常规字符串。 Python 尝试将常规字符串转换为 Unicode,这是更通用的类型,但是因为您没有指定显式转换,所以它使用默认的 ASCII 编解码器,而 ASCII 无法处理字节值更大的字符大于 127。不幸的是,其中一些确实出现在字符串 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 中的默认值。

    【讨论】:

      【解决方案2】:

      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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-06-13
        • 2010-10-04
        • 1970-01-01
        • 1970-01-01
        • 2011-07-07
        • 2016-08-14
        • 1970-01-01
        相关资源
        最近更新 更多