web-dev-qa-db-fra.com

ElementTree XPath - Sélectionnez l'élément en fonction de l'attribut

J'ai du mal à utiliser l'attribut XPath Selector dans ElementTree, ce que je devrais être capable de faire selon 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 ([)
42
Nick Stinemates

La syntaxe que vous essayez d'utiliser est nouvelle dans ElementTree 1..

Cette version est livrée avec Python 2.7 ou supérieur. Si vous avez Python 2.6 ou moins, vous avez toujours ElementTree 1.2.6 ou moins.

34
Florian Bösch

Il y a plusieurs problèmes dans ce code.

  1. Le buildin ElementTree de Python (ET pour faire court) n'a pas de véritable support XPATH; seulement un sous-ensemble limité Par exemple, il ne prend pas en charge les expressions find-from-root comme //target.

    Remarque: la documentation mentionne " // ", mais uniquement pour les enfants: donc une expression comme .//target est valable; //... Ne l'est pas!

    Il existe une implémentation alternative: lxml qui est plus riche. C'est la couture que la documentation est utilisée, pour le code intégré. Cela ne correspond pas/ne fonctionne pas.

  2. La notation @name Sélectionne les attributs xml - ; l'expression key=value dans une balise xml.

    Cette valeur de nom doit donc être 1 ou 2 pour sélectionner quelque chose dans le document donné. Ou, on peut rechercher des cibles avec un élément enfant 'a': target[a] (Non @).

Pour le document donné, analysé avec le ElementTree intégré (v1.3) à la racine, le code suivant est correct et fonctionne:

  • root.findall(".//target") Trouver les deux cibles
  • root.findall(".//target/a") Trouver deux éléments a
  • root.findall(".//target[a]") Ceci trouve à nouveau les deux éléments cibles, car les deux ont un élément a
  • root.findall(".//target[@name='1']") Trouver uniquement la cible d'abord. Notez que les guillemets autour de 1 sont nécessaires; sinon une SyntaxError est levée
  • root.findall(".//target[a][@name='1']") Également valide; pour trouver cet objectif
  • root.findall(".//target[@name='1']/a") Recherche un seul élément a; ...
19
Albert