Je souhaite utiliser la méthode "findall" pour localiser certains éléments du fichier xml source dans le module ElementTree.
Cependant, le fichier xml source (test.xml) a un espace de noms. Je tronque une partie du fichier xml comme exemple:
<?xml version="1.0" encoding="iso-8859-1"?>
<XML_HEADER xmlns="http://www.test.com">
<TYPE>Updates</TYPE>
<DATE>9/26/2012 10:30:34 AM</DATE>
<COPYRIGHT_NOTICE>All Rights Reserved.</COPYRIGHT_NOTICE>
<LICENSE>newlicense.htm</LICENSE>
<DEAL_LEVEL>
<PAID_OFF>N</PAID_OFF>
</DEAL_LEVEL>
</XML_HEADER>
L'exemple de code python est ci-dessous:
from xml.etree import ElementTree as ET
tree = ET.parse(r"test.xml")
el1 = tree.findall("DEAL_LEVEL/PAID_OFF") # Return None
el2 = tree.findall("{http://www.test.com}DEAL_LEVEL/{http://www.test.com}PAID_OFF") # Return <Element '{http://www.test.com}DEAL_LEVEL/PAID_OFF' at 0xb78b90>
Bien que cela puisse fonctionner, car il existe un espace de noms "{http://www.test.com}", il est très peu pratique d'ajouter un espace de noms devant chaque balise.
Comment puis-je ignorer l'espace de noms lors de l'utilisation de la méthode "find", "findall" et ainsi de suite?
python
namespaces
find
elementtree
findall
KevinLeng
la source
la source
tree.findall("xmlns:DEAL_LEVEL/xmlns:PAID_OFF", namespaces={'xmlns': 'http://www.test.com'})
assez pratique?tree.findall("{0}DEAL_LEVEL/{0}PAID_OFF".format('{http://www.test.com}'))
Réponses:
Au lieu de modifier le document XML lui-même, il est préférable de l'analyser, puis de modifier les balises dans le résultat. De cette façon, vous pouvez gérer plusieurs espaces de noms et alias d'espaces de noms:
Ceci est basé sur la discussion ici: http://bugs.python.org/issue18304
Mise à jour:
rpartition
au lieu departition
s'assure que vous obtenez le nom de la balisepostfix
même s'il n'y a pas d'espace de noms. Ainsi vous pourriez le condenser:la source
et.findall('{*}sometag')
. Et cela modifie aussi l'arborescence des éléments elle-même, pas simplement "effectuer la recherche en ignorant les espaces de noms juste cette fois, sans réanalyser le document, etc., en conservant les informations d'espace de noms". Eh bien, dans ce cas, vous devez de manière observable parcourir l'arborescence et voir par vous-même si le nœud correspond à vos souhaits après avoir supprimé l'espace de noms.Si vous supprimez l'attribut xmlns du xml avant de l'analyser, il n'y aura pas d'espace de noms ajouté à chaque balise de l'arborescence.
la source
=
signe égal.Les réponses jusqu'à présent mettent explicitement la valeur de l'espace de noms dans le script. Pour une solution plus générique, je préférerais extraire l'espace de noms du xml:
Et utilisez-le dans la méthode de recherche:
la source
namespace
Voici une extension de la réponse de nonagon, qui supprime également les espaces de noms des attributs:
UPDATE: ajouté
list()
pour que l'itérateur fonctionne (nécessaire pour Python 3)la source
Améliorer la réponse par ericspod:
Au lieu de changer le mode d'analyse globalement, nous pouvons envelopper cela dans un objet prenant en charge la construction with.
Cela peut ensuite être utilisé comme suit
La beauté de cette méthode est qu'elle ne change aucun comportement pour le code non lié en dehors du bloc with. J'ai fini par créer cela après avoir obtenu des erreurs dans des bibliothèques non liées après avoir utilisé la version d'ericspod qui utilisait également expat.
la source
xml.etree.ElementTree.XMLParser
est en quelque sorte optimisé et le monkey-patchingexpat
n'a absolument aucun effet.Vous pouvez également utiliser la construction de formatage de chaîne élégante:
ou, si vous êtes sûr que PAID_OFF n'apparaît qu'à un seul niveau de l'arborescence:
la source
Si vous utilisez
ElementTree
et non,cElementTree
vous pouvez forcer Expat à ignorer le traitement de l'espace de noms en remplaçantParserCreate()
:ElementTree
essaie d'utiliser Expat en appelantParserCreate()
mais ne fournit aucune option pour ne pas fournir de chaîne de séparation d'espace de noms, le code ci-dessus le fera ignorer mais sachez que cela pourrait casser d'autres choses.la source
ElementTree.fromstring(s, parser=None)
j'essaye de lui passer un analyseur.Je suis peut-être en retard pour cela, mais je ne pense pas que ce
re.sub
soit une bonne solution.Cependant la réécriture
xml.parsers.expat
ne fonctionne pas pour les versions Python 3.x,Le principal coupable est la
xml/etree/ElementTree.py
vue en bas du code sourceCe qui est un peu triste.
La solution est de s'en débarrasser d'abord.
Testé sur Python 3.6.
L'
try
instruction Try est utile au cas où quelque part dans votre code vous rechargez ou importez un module deux fois, vous obtenez des erreurs étranges commebtw damn le code source etree semble vraiment désordonné.
la source
Unissons la réponse de nonagon avec la réponse de mzjn à une question connexe :
En utilisant cette fonction, nous:
Créez un itérateur pour obtenir les deux espaces de noms et un objet d'arborescence analysé .
Itérez sur l'itérateur créé pour obtenir les espaces de noms dict que nous pouvons plus tard passer dans chacun
find()
oufindall()
appeler comme suggéré par iMom0 .Je pense que c'est la meilleure approche tout autour car il n'y a aucune manipulation ni d'un XML source ni de la
xml.etree.ElementTree
sortie analysée résultante impliquée.Je voudrais également attribuer à la réponse de Barny une pièce essentielle de ce puzzle (que vous pouvez obtenir la racine analysée de l'itérateur). Jusque-là, j'ai parcouru l'arborescence XML deux fois dans mon application (une fois pour obtenir des espaces de noms, une seconde pour une racine).
la source
find()
etfindall()
. Vous alimentez simplement ces méthodes avec le dict des espaces de nomsparse_xml()
et utilisez le préfixe de l'espace de noms dans vos requêtes. Exemple:et_element.findall(".//some_ns_prefix:some_xml_tag", namespaces=xml_namespaces)