374 votes

Comment sélectionner le premier élément avec un attribut spécifique en utilisant XPath

Le XPath bookstore/book[1] sélectionne le premier nœud de livre sous bookstore .

Comment puis-je sélectionner le premier nœud qui correspond à une condition plus compliquée, par exemple le premier nœud qui correspond à la condition suivante /bookstore/book[@location='US']

545voto

Jonathan Fingland Points 26224

Utilisez :

(/bookstore/book[@location='US'])[1]

Cela permettra d'obtenir d'abord les éléments du livre dont l'attribut location est égal à "US". Ensuite, elle sélectionnera le premier nœud de cet ensemble. Notez l'utilisation des parenthèses, qui sont requises par certaines implémentations.

Notez que ce n'est pas la même chose que /bookstore/book[1][@location='US'] sauf si le premier élément possède également cet attribut de localisation.

0 votes

Comment faire de même pour //bookstore/book[@location='US'] ?

7 votes

Cela permettra d'obtenir tous les livres de "US". (/bookstore/book[@location='US'])[1] obtiendra le premier livre.

3 votes

@KevinDriedger /bookstore/book[@location='US'][1] ne renvoie pas tous les livres des États-Unis. Je l'ai testé plusieurs fois et sous différentes implémentations xpath de langues différentes. /bookstore/book[@location='US'][1] renvoie le premier livre 'US' sous une librairie. S'il y a plusieurs librairies, elle renvoie le premier livre de chacune d'entre elles. C'est ce que le PO a demandé (le premier nœud sous librairie). Votre version ne renvoie qu'un seul livre de toutes les librairies (la première correspondance).

198voto

tkurki Points 821

/bookstore/book[@location='US'][1] ne fonctionne qu'avec une structure simple.

Ajoutez un peu plus de structure et les choses se brisent.

Avec-

<bookstore>
 <category>
  <book location="US">A1</book>
  <book location="FIN">A2</book>
 </category>
 <category>
  <book location="FIN">B1</book>
  <book location="US">B2</book>
 </category>
</bookstore> 

/bookstore/category/book[@location='US'][1] donne

<book location="US">A1</book>
<book location="US">B2</book>

et non "le premier nœud qui correspond à une condition plus compliquée". /bookstore/category/book[@location='US'][2] ne renvoie rien.

Avec les parenthèses, vous pouvez obtenir le résultat recherché par la question initiale :

(/bookstore/category/book[@location='US'])[1] donne

<book location="US">A1</book>

et (/bookstore/category/book[@location='US'])[2] fonctionne comme prévu.

12 votes

Auteur de la réponse acceptée ici. La question de l'OP concernait /bookstore/book[1] et NON (/bookstore/book)[1] . Le cas que vous avez fourni n'est pas le même que celui que le PO a demandé. Vraisemblablement, le PO a accepté ma réponse car elle répondait à ses attentes (et à sa demande).

0 votes

Cette réponse m'a aidé dans ce cas particulier. Quelqu'un peut-il expliquer pourquoi il ne gère pas les "situations plus compliquées" ? Puisque fondamentalement il trouve une liste avec deux éléments, le [2] devrait juste le prendre (dans mon monde).

0 votes

Je trouve aussi que cette réponse est plus correcte que la réponse choisie, car dans mon cas, j'avais aussi une structure plus complexe où le simple fait d'ajouter [1] donnait plusieurs nœuds. Merci !

61voto

Tomalak Points 150423

Comme explication à la réponse de Jonathan Fingland :

  • plusieurs conditions dans le même prédicat ( [position()=1 and @location='US'] ) doit être vrai dans son ensemble
  • des conditions multiples dans des prédicats consécutifs ( [position()=1][@location='US'] ) doit être vrai l'un après l'autre
  • cela implique que [position()=1][@location='US'] != [@location='US'][position()=1]
    tandis que [position()=1 and @location='US'] == [@location='US' and position()=1]
  • indice : un solitaire [position()=1] peut être abrégé en [1]

Vous pouvez construire des expressions complexes dans les prédicats avec les opérateurs booléens " and " et " or ", et avec les fonctions XPath booléennes not() , true() y false() . De plus, vous pouvez mettre les sous-expressions entre parenthèses.

0 votes

Est-il possible d'avoir un tableau de lieux (comme [1,3,5:7,9]) sans utiliser plusieurs opérateurs "et" ?

1 votes

@M.HosseinRahimi Dans XPath 1.0, non. Dans XPath 2.0, les séquences et les = opérateur font l'affaire : [position() = (1,3,5,6,7,9)] .

16voto

Gee-Bee Points 388

Le moyen le plus simple de trouver le premier noeud d'un livre en anglais (dans l'ensemble du document), en prenant en considération un fichier xml structuré plus compliqué, comme par exemple :

<bookstore>
 <category>
  <book location="US">A1</book>
  <book location="FIN">A2</book>
 </category>
 <category>
  <book location="FIN">B1</book>
  <book location="US">B2</book>
 </category>
</bookstore> 

est une expression xpath :

/descendant::book[@location='US'][1]

0 votes

Je ne sais pas pourquoi vous avez ajouté "catégorie" au xml (présumé). Je vote négativement parce qu'il répond à une question que l'OP n'a pas posée.

12voto

iZian Points 295
    <bookstore>
     <book location="US">A1</book>
     <category>
      <book location="US">B1</book>
      <book location="FIN">B2</book>
     </category>
     <section>
      <book location="FIN">C1</book>
      <book location="US">C2</book>
     </section>
    </bookstore> 

Compte tenu de ce qui précède, vous pouvez sélectionner le premier livre avec

(//book[@location='US'])[1]

Et cela trouvera le premier partout où il y a une localisation aux États-Unis. [A1]

//book[@location='US']

Renvoie l'ensemble de nœuds contenant tous les livres dont la localisation est US. [A1,B1,C2]

(//category/book[@location='US'])[1]

Renvoie la première localisation de livre US qui existe dans une catégorie n'importe où dans le document. [B1]

(/bookstore//book[@location='US'])[1]

renverra le premier livre dont la localisation est US et qui existe n'importe où sous l'élément racine bookstore ; rendant la partie /bookstore superflue. [A1]

En réponse directe :

/bookstore/book[@location='US'][1]

Vous renverra le premier noeud de l'élément livre avec l'emplacement US qui est sous librairie [A1].

Par ailleurs, si vous vouliez, dans cet exemple, trouver le premier livre américain qui n'est pas un enfant direct de bookstore :

(/bookstore/*//book[@location='US'])[1]

0 votes

Je ne sais pas pourquoi vous avez ajouté "catégorie" au xml (présumé). Je vote négativement parce qu'il répond à une question que l'OP n'a pas posée.

0 votes

@samwyse parce que l'OP n'a pas fourni plus de contexte sur les autres informations contenues dans leurs données sources. Vous répondez donc en fonction de ce que vous pensez que leurs données pourraient être, et vous fournissez un contexte plus large afin que le PO et les personnes qui trouvent cette question pour les mêmes problèmes ou des problèmes similaires puissent en apprendre davantage en utilisant des exemples pratiques. Vous remarquerez que j'ai un livre dans la rubrique librairie. Contrairement à vos autres réponses copier-coller.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X