ElementTree XPath - Sélection d'un élément en fonction d'un attribut
-
03-07-2019 - |
Question
Je ne parviens pas à utiliser l'attribut XPath Selector dans ElementTree, ce que je devrais pouvoir utiliser conformément à Documentation
Voici un exemple de code
XML
<root>
<target name="1">
<a></a>
<b></b>
</target>
<target name="2">
<a></a>
<b></b>
</target>
</root>
Python
def parse(document):
root = et.parse(document)
for target in root.findall("//target[@name='a']"):
print target._children
Je reçois l'exception suivante:
expected path separator ([)
La solution
La syntaxe que vous essayez d'utiliser est nouvelle dans ElementTree 1.3 .
Cette version est fournie avec Python 2.7 ou une version ultérieure. Si vous avez Python 2.6 ou moins, vous avez toujours ElementTree 1.2.6 ou moins.
Autres conseils
Il y a plusieurs problèmes dans ce code.
-
La construction de Python ElementTree (ET en abrégé) n’a pas de réel support XPATH; par exemple, il ne prend pas en charge les expressions find-from-root telles que
// target
.Remarque: la documentation . mentionne " // ", mais uniquement pour les enfants: une expression comme
.// la cible
est valide;// ...
n'est pas!Il existe une autre implémentation: lxml , qui est plus riche. C'est la documentation qui est utilisée pour le code intégré. Cela ne correspond pas à / travail.
-
La notation
@name
sélectionne les attributs xml- ; l'expressionkey = value
dans une balise xml.Donc, ce nom-valeur doit être 1 ou 2 pour sélectionner quelque chose dans le document donné. Vous pouvez également rechercher des cibles avec un élément 'a' :
cible [a]
(no @).
Pour le document donné, analysé avec root dans ElementTree (v1.3), le code suivant est correct et fonctionne:
-
root.findall (".// cible")
Trouver les deux cibles -
root.findall (".// cible / a")
Recherche deux éléments a -
root.findall (".// cible [a]")
Ceci trouve à nouveau les deux éléments cible, car ils ont tous les deux un élément -
root.findall (".// cible [@ name = '1']")
Recherchez uniquement la première cible. Notez que les guillemets autour de 1 sont nécessaires; sinon une SyntaxError est levée -
root.findall (".// cible [a] [@ name = '1']")
Aussi valide; pour trouver cette cible -
root.findall (".// cible [@ name = '1'] / a")
Recherche un seul élément a; ...