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 &#8; и не может произойти просто.

Если вам нужно обработать этот фрагмент 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]+")