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?
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)
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 ...
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 
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.
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')
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é
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.
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]+")
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.
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".