ParseError: неправильно сформированный (недопустимый токен) с использованием cElementTree
Я получаю строки xml из внешнего источника, который может содержать незапланированный пользовательский контент.
следующая строка xml дала ParseError в cElementTree
:
>>> print repr(s)
'<Comment>ddddddddx08x08x08x08x08x08_____</Comment>'
>>> import xml.etree.cElementTree as ET
>>> ET.XML(s)
Traceback (most recent call last):
File "<pyshell#4>", line 1, in <module>
ET.XML(s)
File "<string>", line 106, in XML
ParseError: not well-formed (invalid token): line 1, column 17
есть ли способ заставить cElementTree не жаловаться?
9 ответов
кажется, жалуются на \x08
вам нужно будет избежать этого.
Edit:
или вы можете заставить парсер игнорировать ошибки, используя recover
from lxml import etree
parser = etree.XMLParser(recover=True)
etree.fromstring(xmlstring, parser=parser)
У меня была такая же ошибка (с ElementTree). В моем случае это было из-за кодировок, и я смог решить его без использования внешней библиотеки. Надеюсь, это поможет другим людям найти этот вопрос на основе названия. (ссылка)
import xml.etree.ElementTree as ET
parser = ET.XMLParser(encoding="utf-8")
tree = ET.fromstring(xmlstring, parser=parser)
редактировать: основываясь на комментариях, этот ответ может быть устаревшим. Но это сработало, когда на него ответили...
посмотреть ответ к другому вопросу и по части спецификации XML.
backspace U + 0008 является недопустимым символом в XML-документах. Он должен быть представлен как escaped entity 
и не может произойти просто.
Если вам нужно обработать этот фрагмент XML, вы должны заменить \x08
на s
перед подачей его в синтаксический анализатор XML.
решение для gottcha для меня, используя ElementTree Python... это имеет недопустимую ошибку токена:
# -*- coding: utf-8 -*-
import xml.etree.ElementTree as ET
xml = u"""<?xml version='1.0' encoding='utf8'?>
<osm generator="pycrocosm server" version="0.6"><changeset created_at="2017-09-06T19:26:50.302136+00:00" id="273" max_lat="0.0" max_lon="0.0" min_lat="0.0" min_lon="0.0" open="true" uid="345" user="john"><tag k="test" v="Съешь же ещё этих мягких французских булок да выпей чаю" /><tag k="foo" v="bar" /><discussion><comment data="2015-01-01T18:56:48Z" uid="1841" user="metaodi"><text>Did you verify those street names?</text></comment></discussion></changeset></osm>"""
xmltest = ET.fromstring(xml.encode("utf-8"))
однако он работает с добавлением дефиса в типе кодировки:
<?xml version='1.0' encoding='utf-8'?>
самое странное. кто-то нашел эту сноску в python docs:
строка кодировки, включенная в вывод XML, должна соответствовать соответствующий стандарт. Например," UTF-8 "является допустимым, но" UTF8 не.
Я застрял с аналогичной проблемой. Наконец, выяснил, что было основной причиной в моем конкретном случае. Если Вы читаете данные из нескольких XML-файлов, которые лежат в одной папке, вы будете разбирать также .Файл DS_Store. Перед разбором добавьте это условие
for file in files:
if file.endswith('.xml'):
run_your_code...
этот трюк помог мне так же
что помогло мне с этой ошибкой, был ответ Хуана -https://stackoverflow.com/a/20204635/4433222 Но этого было недостаточно - после борьбы я узнал, что XML-файл должен быть сохранен с UTF-8 без кодировки BOM.
решение не работало для" нормального " UTF-8.
Это скорее всего ошибка кодировки. Например, у меня был xml-файл, закодированный в UTF-8-BOM (проверено из меню кодировки Notepad++), и получил аналогичное сообщение об ошибке.
обходной путь (Python 3.6)
import io
from xml.etree import ElementTree as ET
with io.open(file, 'r', encoding='utf-8-sig') as f:
contents = f.read()
tree = ET.fromstring(contents)
Проверьте кодировку вашего xml-файла. Если он использует другую кодировку, измените 'utf-8-sig' соответственно.
ни одно из вышеперечисленных исправлений не сработало для меня. Единственное, что сработало, - это использовать BeautifulSoup
вместо ElementTree
следующим образом:
from bs4 import BeautifulSoup
with open("data/myfile.xml") as fp:
soup = BeautifulSoup(fp, 'xml')
тогда вы можете искать дерево как:
soup.find_all('mytag')
я попробовал другие решения в ответах здесь, но не повезло. Поскольку мне нужно было извлечь значение только из одного xml-узла, я сдался и написал свою функцию для этого:
def ParseXmlTagContents(source, tag, tagContentsRegex):
openTagString = "<"+tag+">"
closeTagString = "</"+tag+">"
found = re.search(openTagString + tagContentsRegex + closeTagString, source)
if found:
start = found.regs[0][0]
end = found.regs[0][1]
return source[start+len(openTagString):end-len(closeTagString)]
return ""
пример использования:
<?xml version="1.0" encoding="utf-16"?>
<parentNode>
<childNode>123</childNode>
</parentNode>
ParseXmlTagContents(xmlString, "childNode", "[0-9]+")