web-dev-qa-db-fra.com

ParseError: pas bien formé (jeton invalide) avec cElementTree

Je reçois des chaînes XML d'une source externe pouvant contenir du contenu non authentifié fourni par l'utilisateur.

La chaîne XML suivante a donné une ParseError dans cElementTree:

>>> print repr(s)
'<Comment>dddddddd\x08\x08\x08\x08\x08\x08_____</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

Existe-t-il un moyen de faire en sorte que cElementTree ne se plaint pas?

15
BioGeek

Il semble se plaindre de \x08, vous devrez y échapper.

Modifier:  

Ou vous pouvez demander à l'analyseur d'ignorer les erreurs à l'aide de recover

from lxml import etree
parser = etree.XMLParser(recover=True)
etree.fromstring(xmlstring, parser=parser)
23
iabdalkader

J'avais la même erreur (avec ElementTree). Dans mon cas, c'était à cause d'encodages, et j'ai pu le résoudre sans avoir à utiliser une bibliothèque externe. J'espère que cela aidera d'autres personnes à trouver cette question en se basant sur le titre. ( référence )

import xml.etree.ElementTree as ET
parser = ET.XMLParser(encoding="utf-8")
tree = ET.fromstring(xmlstring, parser=parser)

EDIT: Selon les commentaires, cette réponse pourrait être obsolète. Mais cela a fonctionné à l'époque où il a été répondu ...

21
juan

Voir cette réponse à une autre question et le conformément à la partie de la spécification XML.

Le retour arrière U + 0008 est un caractère non valide dans les documents XML. Il doit être représenté en tant qu'entité échappée &#8; et ne peut pas apparaître clairement.

Si vous devez traiter cet extrait de code XML, vous devez remplacer \x08 dans s avant de l'insérer dans un analyseur XML.

7
Boldewyn

Aucune des corrections ci-dessus n'a fonctionné pour moi. La seule chose qui a fonctionné était d'utiliser BeautifulSoup au lieu de ElementTree comme suit:

from bs4 import BeautifulSoup

with open("data/myfile.xml") as fp:
    soup = BeautifulSoup(fp, 'xml')

Ensuite, vous pouvez rechercher l'arbre comme:

soup.find_all('mytag')
1
tsando

J'ai été coincé avec un problème similaire. Enfin découvert quelle était la cause première de mon cas particulier. Si vous lisez les données de plusieurs fichiers XML situés dans le même dossier, vous analyserez également le fichier .DS_Store . Avant l'analyse, ajoutez cette condition.

for file in files:
    if file.endswith('.xml'):
       run_your_code...

Cette astuce m'a aussi aidé

1
Yura Vasiliuk

Une solution pour gottcha pour moi, utilisant ElementTree de Python ... cela a l'erreur de jeton invalide

# -*- 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"))

Cependant, cela fonctionne avec l'ajout d'un trait d'union dans le type d'encodage:

<?xml version='1.0' encoding='utf-8'?>

Le plus étrange. Quelqu'un a trouvé cette note de bas de page dans la documentation python :

La chaîne de codage incluse dans la sortie XML doit être conforme au normes appropriées. Par exemple, «UTF-8» est valide, mais «UTF8» est ne pas.

1
TimSC

J'ai essayé les autres solutions dans les réponses ici mais n'ai pas eu de chance. Comme je n'avais besoin que d'extraire la valeur d'un seul noeud xml, j'ai écrit et écrit ma fonction pour le faire:

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 ""

Exemple d'utilisation serait:

<?xml version="1.0" encoding="utf-16"?>
<parentNode>
    <childNode>123</childNode>
</parentNode>

ParseXmlTagContents(xmlString, "childNode", "[0-9]+")
0
the_doc

C'est très probablement une erreur d'encodage. Par exemple, j'avais un fichier XML encodé en UTF-8-BOM (vérifié à partir du menu Encodage du Notepad ++) et j'ai reçu un message d'erreur similaire. 

La solution de contournement (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)

Vérifiez l'encodage de votre fichier XML. S'il utilise un codage différent, changez le 'utf-8-sig' en conséquence.

0
np8

Ce qui m'a aidé avec cette erreur était la réponse de Juan - https://stackoverflow.com/a/20204635/4433222 Mais cela ne suffisait pas - après avoir lutté, j'ai découvert qu'un fichier XML devait être enregistré avec UTF-8 sans codage BOM.

La solution ne fonctionnait pas pour UTF-8 "normal".

0
Konrad