Уведомления

Группа в Telegram: @pythonsu

#1 Апрель 4, 2019 17:44:15

Chrome7
Зарегистрирован: 2019-04-04
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

Ошибка "ElementTree.ParseError: not well-formed"

Доброго времени суток.

Есть у меня замечательный следующий код

 import xml.etree.cElementTree as ET
if __name__ == "__main__":
    tree = ET.parse('C:/ForTests/123.xml', ET.XMLParser(encoding='utf-8'))
    root = tree.getroot()
    for child in root:
        for element in child:
            print(element.tag, ":", element.text)

И при его запуске появляется следующая ошибка:

“xml.etree.ElementTree.ParseError: not well-formed (invalid token): line 689, column 18

Process finished with exit code 1”

Я открываю файл 123.xml, нахожу 689 строку. Вот она:
<Name>Town&Country</Name>

И ругается питон, я уверен, на этот самый апперсанд.

И вот он, собственно, вопрос:
Почему он ругается, если я выставил значение парсера как ET.XMLParser(encoding='utf-8') ?
Ну или как это исправить?

Если такая ошибка уже встречалась на форуме, а скорее всего так и есть, пожалуйста, перенаправьте меня на эту темку. Порывшись через Ctrl+F по форуму ничего не нашел.

Офлайн

#2 Апрель 4, 2019 18:05:46

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

Ошибка "ElementTree.ParseError: not well-formed"

 etree.XMLParser(encoding='utf-8', recover=True)



Офлайн

#3 Апрель 4, 2019 18:41:22

Chrome7
Зарегистрирован: 2019-04-04
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

Ошибка "ElementTree.ParseError: not well-formed"

FishHook

Если я всё правильно понял, то мне необходимо привести код к следующему виду:
 import xml.etree.ElementTree as ET
if __name__ == "__main__":
    tree = ET.parse('C:/ForTests/123.xml', parser=ET.XMLParser(encoding='utf-8', recover=True))
    root = tree.getroot()
    for child in root:
        for element in child:
            print(element.tag, ":", element.text)

В случае запуска которого появляется следующая ошибка:
TypeError: ‘recover’ is an invalid keyword argument for XMLParser()

Офлайн

#4 Апрель 4, 2019 19:03:41

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

Ошибка "ElementTree.ParseError: not well-formed"

Chrome7
Это я видимо с библиотекой lxml перепутал.
Собственно, покажите ваш xml-файл.



Отредактировано FishHook (Апрель 4, 2019 19:04:02)

Офлайн

#5 Апрель 4, 2019 20:46:29

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  252  -
Профиль   Отправить e-mail  

Ошибка "ElementTree.ParseError: not well-formed"

Chrome7
Ну или как это исправить?
Очевидно не парсить невалидные xml файлы. Т.е. бейте тех кто такие файлы сделал.
https://www.w3.org/TR/xml/#syntax
“The ampersand character (&) and the left angle bracket (<) must not appear in their literal form”
Кодировка очевидно тут совершенно не виновата.



Офлайн

#6 Апрель 5, 2019 10:44:11

Chrome7
Зарегистрирован: 2019-04-04
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

Ошибка "ElementTree.ParseError: not well-formed"

FishHook
Chrome7Это я видимо с библиотекой lxml перепутал.Собственно, покажите ваш xml-файл.
Как заметил doza_and, в моем действительно невалидные xml, проверять их нечего.
Самые часто встречаемые ошибки - апперсанд и двойные кавычки в тексте.

doza_and
Меня посадят за массовые избиения. И на билеты по разным городам я потрачусь очень сильно.

В общем, как я понимаю, мне нужно сначала копать в сторону реплейса строк.
И если в случае апперсанда, это должно выглядеть как-то так(не знаю, сработает ли):

 with open("file_path") as file:
    for line in file:
        line = line.replace('&', ' and ')

То как исправить конструкцию с двойными кавычками типа:
<Model =“78051” Name=“3.1 ”ЛИДЕР“” Priority=“0”/>

В ней в Name попадет “3.1 ”, как я понимаю, а дальше у питона возникнет резонный вопрос, что такое ЛИДЕР“”. И он ругнется.
Может подскажете, как можно исправить такую конструкцию?

Офлайн

#7 Апрель 5, 2019 12:46:50

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9716
Репутация: +  842  -
Профиль   Отправить e-mail  

Ошибка "ElementTree.ParseError: not well-formed"

Chrome7
И если в случае апперсанда, это должно выглядеть как-то так
Не, это неправильно.

Вот, например, валидный кусок XML
<elem>&amp;</elem>
но твой код с простым .replace()'ом его испортит.

Лучше выяснить, откуда идут невалидные XML-файлы. Если это нельзя исправить, то можно написать транслятор, который невалидные XML-файлы восстанавливает и превращает в валидные файлы, либо поискать такой транслятор в уже готовом виде. Такой транслятор - это не просто набор .replace()'ов, а, как правило, детерминированный конечный автомат с магазинной памятью (ДКА со стеком). И только после такой трансляции можно разбирать валидный файл через XML-парсер.



Отредактировано py.user.next (Апрель 5, 2019 12:51:22)

Офлайн

#8 Апрель 5, 2019 21:24:03

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  252  -
Профиль   Отправить e-mail  

Ошибка "ElementTree.ParseError: not well-formed"

Chrome7
Меня посадят за массовые избиения.
Ну вы помягче. Отправьте поставщикам файлов сообщение что у них невалидные файлы, дайте ссылку на сайт валидатор, чтобы они могли сами проверить что вам выдают. Напишите что не будете обрабатывать такие файлы….

Это конечно не всегда возможно….
Тогда попросите их описать синтаксис файла при помощи формальной грамматики.
Тут возможно вас просто не поймут….

Поскольку ошибки в xml правило а не исключение то некоторые библиотеки предлагают возможность продолжить парсинг после возникновения ошибок recover=True

https://lxml.de/api/lxml.etree.XMLParser-class.html

При этом вы потеряете часть данных.

Поскольку это не xml файл то нечего его парсить как xml. Возможно вам самим надо тогда при помощи https://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D1%80%D0%B0%D1%82%D0%BD%D0%B0%D1%8F_%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0
построить грамматику файлов, а потом сделать парсер для них. При этом никаких гарантий что завтра ваш парсер не откажет нет (поэтому и надо всеми силами настаивать чтобы исправления были на стадии генерации файлов).



Офлайн

#9 Апрель 8, 2019 12:12:51

Chrome7
Зарегистрирован: 2019-04-04
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

Ошибка "ElementTree.ParseError: not well-formed"

doza_and
Спасибо за помощь.
К сожалению, с поставщиками этих xml-ек очень тяжело связаться. Это разработка в других компаниях.


И небольшое обращение в будущее, если кто-нибудь столкнется с похожей ошибкой.
Гораздо легче исправить xml-файл, чем пытаться найти способ обойти в нём ошибки.
Я решил проблему следующим образом:
     with open(inputfile, 'r', encoding='utf-8') as file:
        for line in file:
            line = line.replace('&', ' and ')
            text.append(line)
По итогу мы получаем “исправленный” xml-файл в переменной text. Распарсить которую уже можно будет без ошибок.

Выше
py.user.next
замечал, что это не корректный способ, но в моем случае он отработал идеально.
Смотрите, какие ошибки у вас в строках, делайте реплейсеры, прогоняйте через них текст.
Подробнее о том, как это корректно сделать можно прочитать здесь:
https://www.tjohearn.com/2018/01/24/safe-ampersand-parsing-in-xml-files/

Офлайн

#10 Апрель 8, 2019 23:04:39

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9716
Репутация: +  842  -
Профиль   Отправить e-mail  

Ошибка "ElementTree.ParseError: not well-formed"

Chrome7
замечал, что это не корректный способ, но в моем случае он отработал идеально.
Завтра тебе пришлют новый документ, в котором будет смесь из амперсандов и сущностей - и твой сегодняшний код сломает завтрашний документ, повредив сущности.

То есть ты написал костыль. Пока человек идёт на костылях по улице, это выглядит приемлемо и похоже на обычного человека без костылей, но если вдруг ему нужно будет успеть на автобус, двери которого вот-вот закроются, то он не только его не догонит, но ещё и упадёт прямо на улице, не удержав костыли при беге, и будет очень долго валяться. Что хаки, что костыли, - это всё вредные вещи, которые на первый взгляд выглядят прекрасно, но эта прекрасность обманчива и очень часто потом выходит таким боком, что даже изсправить ничего не возможно, остаётся только всю программу заново писать, либо отказаться от её применения к новым данным.

Chrome7
Подробнее о том, как это корректно сделать можно прочитать здесь:
Во-первых, у него слишком короткое регулярное выражение, так как сущностей в XML может быть больше.
https://www.w3.org/TR/xml-entity-names/

И символы юникода также могут кодироваться через числовой код (в 10-чной и/или 16-ричной системе) с помощью амперсанда.
https://en.wikipedia.org/wiki/XML
All permitted Unicode characters may be represented with a numeric character reference.

Во-вторых, даже если просто заменить кавычку с сущности &apos; на простую кавычку, его код не сможет это исправить, потому что расчитан только на неправильно выраженный амперсанд в xml-документе, и исправить свой код, чтобы он ещё и кавычку учитывал, он не сможет, так как у кавычки гораздо больше смежных случаев, чем у амперсанда.

А как же это исправить? Выше я написал, как: надо сделать простейший транслятор, который сначала идентифицирует именно тот амперсанд в контексте и/или именно ту кавычку в контексте и только после этого заменит их. При этом будет гарантировано, что он не заменяет не тот амперсанд или не ту кавычку. То есть нужно написать лексический анализатор на базе ДКА. В общем случае понадобится магазин, но для частного случая можно и без магазина обойтись. Вот из-за того, что этот парнишка не знает программирование глубже школьника, он и побирается по всяким сайтам и в конечном итоге приходит к полурабочему решению.



Отредактировано py.user.next (Апрель 8, 2019 23:29:25)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version