Obtenir les nœuds où le nœud enfant contient un attribut

116

Supposons que j'ai le XML suivant:

<book category="CLASSICS">
  <title lang="it">Purgatorio</title>
  <author>Dante Alighieri</author>
  <year>1308</year>
  <price>30.00</price>
</book>

<book category="CLASSICS">
  <title lang="it">Inferno</title>
  <author>Dante Alighieri</author>
  <year>1308</year>
  <price>30.00</price>
</book>

<book category="CHILDREN">
  <title lang="en">Harry Potter</title>
  <author>J K. Rowling</author>
  <year>2005</year>
  <price>29.99</price>
</book>

<book category="WEB">
  <title lang="en">XQuery Kick Start</title>
  <author>James McGovern</author>
  <author>Per Bothner</author>
  <author>Kurt Cagle</author>
  <author>James Linn</author>
  <author>Vaidyanathan Nagarajan</author>
  <year>2003</year>
  <price>49.99</price>
</book>

<book category="WEB">
  <title lang="en">Learning XML</title>
  <author>Erik T. Ray</author>
  <year>2003</year>
  <price>39.95</price>
</book>

Je voudrais faire un xpath qui récupère tous les nœuds de livre qui ont un nœud de titre avec un attribut de langue "it".

Ma tentative ressemblait à ceci:

//book[title[@lang='it']]

Mais cela n'a pas fonctionné. J'espère récupérer les nœuds:

<book category="CLASSICS">
  <title lang="it">Purgatorio</title>
  <author>Dante Alighieri</author>
  <year>1308</year>
  <price>30.00</price>
</book>

<book category="CLASSICS">
  <title lang="it">Inferno</title>
  <author>Dante Alighieri</author>
  <year>1308</year>
  <price>30.00</price>
</book>

Des indices?

Uwe Keim
la source
De quelle implémentation XPath s'agit-il?
Pavel Minaev

Réponses:

175

Essayer

//book[title/@lang = 'it']

Cela se lit:

  • obtenir tous les bookéléments
    • qui ont au moins un title
      • qui a un attribut lang
        • avec une valeur de "it"

Vous trouverez peut-être cela utile - c'est un article intitulé "XPath en cinq paragraphes" de Ronald Bourret.

Mais en toute honnêteté, //book[title[@lang='it']]et ce qui précède devrait être équivalent, à moins que votre moteur XPath ait des «problèmes». Il peut donc s'agir d'un élément du code ou de l'exemple XML que vous ne nous montrez pas - par exemple, votre exemple est un fragment XML. Se pourrait-il que l'élément racine ait un espace de noms et que vous ne comptez pas pour cela dans votre requête? Et vous nous avez seulement dit que cela n'a pas fonctionné, mais vous ne nous avez pas dit quels résultats vous aviez obtenus.

Lavinio
la source
4
Comment faire la même chose si ce titlen'est pas un enfant direct de book, mais quelque part plus profond et on ne sait pas où exactement? //book[/title/@lang = 'it']ne semble pas fonctionner?
Martin Konicek
5
Martin, vous pouvez utiliser //book[.//title/@lang = 'it']. Je crois que le truc est le "." au début de la condition.
Bruno Caponi
1
Merci pour le lien, excellent article. J'utilise xPath depuis des années mais cela m'a vraiment aidé à comprendre la logique sous-jacente!
swensor le
57

Des années plus tard, mais une option utile serait d'utiliser les axes XPath ( https://www.w3schools.com/xml/xpath_axes.asp ). Plus précisément, vous cherchez à utiliser les axes descendants .

Je pense que cet exemple ferait l'affaire:

//book[descendant::title[@lang='it']]

Cela vous permet de sélectionner tous les bookéléments qui contiennent un titleélément enfant (quelle que soit sa profondeur d'imbrication) contenant une valeur d'attribut de langue égale à «it».

Je ne peux pas dire avec certitude si cette réponse est pertinente ou non pour l'année 2009 car je ne suis pas sûr à 100% que les axes XPath existaient à ce moment-là. Ce que je peux confirmer, c'est qu'ils existent aujourd'hui et je les ai trouvés extrêmement utiles dans la navigation XPath et je suis sûr que vous le ferez également.

wes.hysell
la source
12
//book[title[@lang='it']]

est en fait équivalent à

 //book[title/@lang = 'it']

Je l'ai essayé en utilisant vtd-xml, les deux expressions génèrent le même résultat ... quel moteur de traitement xpath avez-vous utilisé? Je suppose qu'il y a un problème de conformité Ci-dessous le code

import com.ximpleware.*;
public class test1 {
  public static void main(String[] s) throws Exception{
      VTDGen vg = new VTDGen();
      if (vg.parseFile("c:/books.xml", true)){
          VTDNav vn = vg.getNav();
          AutoPilot ap = new AutoPilot(vn);
          ap.selectXPath("//book[title[@lang='it']]");
                  //ap.selectXPath("//book[title/@lang='it']");

          int i;
          while((i=ap.evalXPath())!=-1){
              System.out.println("index ==>"+i);
          }
          /*if (vn.endsWith(i, "< test")){
             System.out.println(" good ");  
          }else
              System.out.println(" bad ");*/

      }
  }
}
vtd-xml-author
la source
+1 que c'est un problème de conformité et que la syntaxe génère le même ensemble de nœuds. Un code similaire en C # fonctionne également.
Zach Bonham
-1: M. Zhang, j'essayais de vous rendre service en supprimant le code non pertinent à la question. Cela m'a permis de ne pas vous rejeter, ce que je sens maintenant devoir faire. Notez qu'aucune autre réponse n'inclut de code pour appeler appeler la requête.
John Saunders
6
+1: Parce que je ne peux pas comprendre de quoi parle M. Saunders - aucune autre réponse n'a ajouté de code, et cette réponse montre le code utilisé pour que nous puissions 1: valider ses méthodes et 2: effectuer son test nous-mêmes. Le code est court et facile à lire. Je ne vois pas le problème.
DuckPuppy
4

Je pense que votre propre suggestion est correcte, mais le XML n'est pas tout à fait valide. Si vous exécutez le //book[title[@lang='it']]on, <root>[Your"XML"Here]</root>les testeurs xPath en ligne gratuits comme celui- ci trouveront le résultat attendu.

Joakim Byg
la source
2

Essayez d'utiliser cette expression xPath:

//book/title[@lang='it']/..

Cela devrait vous donner tous les nœuds de livre dans "it" lang

user1113000
la source
2
le résultat de cette expression est les nœuds de titre, pas les nœuds de livre
Caleth
2
Ce n'est pas vrai. Il renverra des nœuds de livre (ces deux points à la fin doivent viser le nœud supérieur du nœud de titre).
user1113000