Скрипт синтаксического анализа на основе экспатов не работает в Linux, работает в Windows

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

Проблема в том, что когда я запускаю свои скрипты на работе на компьютере с Windows XP, он работает отлично, но дома, на Ubuntu 10.10, в том же файле я получаю следующую ошибку:
ExpatError: not well-formed (invalid token): line 1, column 0

Файл изначально был закодирован в utf-8, а кодировка, объявленная в теге, была ascii, поэтому попробуйте изменить его на utf-8 (или UTF8 или utf8) без успеха. Поскольку спецификация отсутствовала, я попытался написать ее, но безуспешно. Я также пытался заменить разрыв строки в Windows (CR/LF) на Unix (CR). Также без какого-либо успеха.

Также версия Python на работе - 2.7.1, на моем Ubuntu - 2.6.6, но не думаю, что моя проблема связана с тем, что: я без проблем обновил Python своего рабочего компьютера с 2.6 до 2.7 несколько недель назад.

Поскольку я здесь не эксперт, у меня заканчиваются идеи, есть подсказка?

Изменить: После дальнейшего расследования (у меня сейчас болит голова, я ненавижу проблемы, связанные с Unicode) похоже, что проблема была решена путем правильной установки системных переменных среды LANG, LC_ALL и LANGUAGE в (в моем случае) "fr_FR.utf-8", Я не понимаю, почему они не были поначалу и почему сейчас, это работает...

Я благодарю вас, ребята, за руку!

2 ответа

Решение

Выдержки из документации:

xml.parsers.expat.XML_ERROR_INVALID_TOKEN
Возникает, когда входной байт не может быть правильно назначен символу; например, байт NUL (значение 0) во входном потоке UTF-8.

ExpatError.lineno
Номер строки, в которой была обнаружена ошибка. Первая строка пронумерована 1.

ExpatError.offset
Смещение символа в строку, где произошла ошибка. Первый столбец пронумерован 0.

Сказанное выше указывает на то, что у вас есть проблема с самым первым байтом в вашем файле.

Начните с оригинального файла, который работал в Windows. Отредактируйте свой вопрос, чтобы показать результаты этого:

python -c "print repr(open('win_ok_file.xml', 'rb').read(200))"

который однозначно покажет, что находится в первых 200 байтах в вашем файле.

Также покажите нам урезанную версию вашего кода, которую вы проверили, будет работать в Windows, чтобы преодолеть первоначальную ошибку, но воспроизводит проблему в Linux.

Некоторые утверждения, для чего они стоят:

  • "Файл изначально был закодирован в utf-8, и кодировка, объявленная в теге, была ascii" ... Если кодировка в объявлении XML - "ascii", но в файле присутствуют символы, отличные от ASCII, соответствующие синтаксические анализаторы должны вызвать исключение. Вы уверены, что вы сообщаете?

  • Кодировка по умолчанию для документов XML - UTF-8. Другими словами, если кодировка не упоминается в декларации XML или декларация XML вообще отсутствует, синтаксический анализатор должен декодировать с использованием UTF-8.

  • Помещение спецификации UTF-8 в начале скорее будет мешать, чем помогать.

  • Стандарт XML требует, чтобы парсеры принимали CR как действительный байт в документе XML, а затем немедленно притвориться, что его не существует (за исключением, может быть, элемента сxmlns:space="preserve"). измененияCR LF в LF не очень хорошая идея

И несколько вопросов: сколько байтов в "довольно большом" файле? Рассматривали ли вы использование iterparse() от xml.etree.cElementTree или же lxml?

У меня была та же проблема, и вместо того, чтобы пытаться разобрать файл прямо так:

document = xmltodict.parse("myfile.xml") # Parse the read document string

Я проанализировал его косвенно, предварительно открыв документ XML через объект, например так:

document_file = open("myfile.xml", "r") # Open a file in read-only mode
original_doc = document_file.read() # read the file object
document = xmltodict.parse(original_doc) # Parse the read document string

и это сработало.

Другие вопросы по тегам