Чтение UTF-8 XML и запись его в файл с помощью Python - PullRequest
3 голосов
/ 10 июня 2010

Я пытаюсь проанализировать XML-файл UTF-8 и сохранить некоторые его части в другой файл.Проблема в том, что это мой первый скрипт на Python, и я совершенно сбит с толку из-за проблем с кодировкой символов, которые я нахожу.

Мой скрипт завершается ошибкой сразу, когда он пытается записать не-ascii символ в файл,но он может распечатать его в командной строке (по крайней мере, на некотором уровне)

Вот XML (из частей, которые имеют значение по крайней мере, это * .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?Файлы, которые я пытаюсь сгенерировать, будут использоваться для автоматизации тестирования с Robots Framework.

Ответы [ 2 ]

7 голосов
/ 10 июня 2010

Вам необходимо удалить вызов на 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 (внутреннее представление Python, которое может хранить все символы Unicode) в обычную строку (которая может хранить только однобайтовые символы 0-255).Позже, когда вы создаете строку для записи в выходной файл, names[i] все еще является строкой Unicode, но values[i] является обычной строкой.Python пытается преобразовать обычную строку в Unicode, который является более общим типом, но поскольку вы не указываете явное преобразование, он использует кодек ASCII, который является значением по умолчанию, и ASCII не может обрабатывать символы с байтовыми значениями большечем 127. К сожалению, некоторые из них встречаются в строке values[i], потому что кодировка UTF-8 часто использует эти байты верхнего диапазона.Поэтому Python жалуется, что видит персонажа, с которым не может справиться.Решение, как я уже говорил выше, состоит в том, чтобы отложить преобразование из Unicode в байты до последнего возможного момента, и вы делаете это с помощью версии open с поддержкой Unicode (которая будет обрабатывать кодировку для вас).

Теперь, когда я думаю об этом, вместо того, что я сказал выше, альтернативным решением было бы заменить names[i] на names[i].encode("utf-8").Таким образом, вы также преобразуете names[i] в обычную строку, и у Python нет причин пытаться преобразовать values[i] обратно в Unicode.Хотя можно утверждать, что хорошей практикой является сохранение ваших строк в качестве объектов Юникода до тех пор, пока вы не запишите их в файл ... если ничего больше, я считаю, что unicode становится значением по умолчанию в Python 3.

0 голосов
/ 10 июня 2010

Анализатор 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...