Dapatkan node di mana node anak berisi atribut

116

Misalkan saya memiliki XML berikut ini:

<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>

Saya ingin melakukan xpath yang mengembalikan semua node buku yang memiliki node judul dengan atribut bahasa "it".

Upaya saya terlihat seperti ini:

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

Tapi itu tidak berhasil. Saya berharap untuk mendapatkan kembali node:

<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>

Ada petunjuk?

Uwe Keim
sumber
Implementasi XPath apa ini?
Pavel Minaev

Jawaban:

175

Mencoba

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

Ini berbunyi:

  • dapatkan semua bookelemen
    • yang memiliki setidaknya satu title
      • yang memiliki atribut lang
        • dengan nilai "it"

Anda mungkin menemukan ini membantu - itu sebuah artikel berjudul "XPath di Lima Paragraf" oleh Ronald Bourret.

Tapi sejujurnya, //book[title[@lang='it']]dan di atas harus setara, kecuali mesin XPath Anda memiliki "masalah." Jadi bisa jadi sesuatu dalam kode atau contoh XML yang tidak Anda tunjukkan kepada kami - misalnya, contoh Anda adalah fragmen XML. Mungkinkah elemen root memiliki namespace, dan Anda tidak menghitungnya dalam kueri Anda? Dan Anda hanya memberi tahu kami bahwa itu tidak berhasil, tetapi Anda tidak memberi tahu kami hasil apa yang Anda dapatkan.

lavinio
sumber
4
Bagaimana melakukan hal yang sama jika titlebukan anak langsung dari book, tetapi di suatu tempat yang lebih dalam dan kita tidak tahu persis di mana? //book[/title/@lang = 'it']sepertinya tidak berhasil?
Martin Konicek
5
Martin, Anda bisa menggunakan //book[.//title/@lang = 'it']. Saya yakin triknya adalah "." di awal kondisi.
Bruno Caponi
1
Terima kasih untuk tautannya, artikel bagus. Saya telah menggunakan xPath selama bertahun-tahun tetapi ini sangat membantu saya memahami logika yang mendasarinya!
swensor
57

Bertahun-tahun kemudian, tetapi opsi yang berguna adalah menggunakan Sumbu XPath ( https://www.w3schools.com/xml/xpath_axes.asp ). Lebih khusus lagi, Anda ingin menggunakan sumbu turunan .

Saya yakin contoh ini akan berhasil:

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

Ini memungkinkan Anda untuk memilih semua book elemen yang berisi titleelemen anak (terlepas dari seberapa dalam elemen itu bersarang) yang berisi nilai atribut bahasa yang sama dengan 'it'.

Saya tidak dapat mengatakan dengan pasti apakah jawaban ini relevan dengan tahun 2009 atau tidak karena saya tidak 100% yakin bahwa XPath Axes ada pada saat itu. Apa yang dapat saya konfirmasikan adalah bahwa mereka ada hari ini dan saya telah menemukan mereka sangat berguna dalam navigasi XPath dan saya yakin Anda akan melakukannya juga.

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

sebenarnya setara dengan

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

Saya mencobanya menggunakan vtd-xml, kedua ekspresi tersebut mengeluarkan hasil yang sama ... mesin pengolah xpath apa yang Anda gunakan? Saya kira itu memiliki masalah kesesuaian Di bawah ini adalah kodenya

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
sumber
+1 bahwa ini adalah masalah kepatuhan dan sintaksnya menghasilkan kumpulan node yang sama. Kode serupa di C # juga berfungsi.
Zach Bonham
-1: Tuan Zhang, saya mencoba membantu Anda dengan menghapus kode yang tidak relevan dengan pertanyaan tersebut. Itu memungkinkan saya untuk tidak meremehkan Anda, yang sekarang saya rasa harus saya lakukan. Perhatikan bahwa tidak ada jawaban lain yang menyertakan kode untuk memanggil permintaan tersebut.
John Saunders
6
+1: Karena saya tidak mengerti apa yang Tn. Saunders bicarakan - tidak ada jawaban lain yang menambahkan kode APA PUN, dan jawaban ini menunjukkan kode yang digunakan sehingga kami dapat 1: memvalidasi metodenya dan 2: melakukan pengujiannya sendiri. Kode ini pendek dan mudah dibaca. Saya tidak melihat masalahnya.
DuckPuppy
4

Menurut saya saran Anda sendiri benar, namun xml tidak cukup valid. Jika Anda menjalankan //book[title[@lang='it']]pada <root>[Your"XML"Here]</root>kemudian penguji XPath online gratis seperti salah satu di sini akan menemukan hasil yang diharapkan.

Joakim Byg
sumber
2

Coba gunakan ekspresi xPath ini:

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

Itu akan memberi Anda semua node buku dalam lang "it"

pengguna1113000
sumber
2
hasil dari ekspresi itu adalah node judul, bukan node buku
Caleth
2
Itu tidak benar. Ini akan mengembalikan simpul buku (dua titik di ujung ini mengarah ke simpul atas simpul judul).
pengguna1113000