Cara memilih elemen pertama dengan atribut tertentu menggunakan XPath

300

XPath bookstore/book[1]memilih simpul buku pertama di bawah bookstore.

Bagaimana saya bisa memilih simpul pertama yang cocok dengan kondisi yang lebih rumit, misal simpul pertama yang cocok /bookstore/book[@location='US']

ripper234
sumber

Jawaban:

444

Menggunakan:

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

Ini pertama-tama akan mendapatkan elemen buku dengan atribut lokasi sama dengan 'AS'. Kemudian akan memilih simpul pertama dari set itu. Perhatikan penggunaan tanda kurung, yang diperlukan oleh beberapa implementasi.

Catatan, ini tidak sama dengan /bookstore/book[1][@location='US']kecuali elemen pertama juga memiliki atribut lokasi tersebut.

Jonathan Fingland
sumber
Bagaimana saya bisa melakukan hal yang sama untuk // toko buku / book [@ location = 'US']?
Alexander V. Ilyin
7
Ini akan mendapatkan semua buku dari 'AS'. (/ toko buku / book [@ location = 'US']) [1] akan mendapatkan yang pertama.
Kevin Driedger
3
@KevinDriedger /bookstore/book[@location='US'][1]tidak mengembalikan semua buku dari 'AS'. Saya telah mengujinya berkali-kali dan di bawah implementasi xpath bahasa yang berbeda. /bookstore/book[@location='US'][1]mengembalikan buku 'AS' pertama di bawah toko buku. Jika ada toko buku mutiple, maka itu akan mengembalikan yang pertama dari masing-masing. Inilah yang diminta OP (simpul pertama di bawah toko buku). Versi Anda hanya mengembalikan satu buku dari semua toko buku (pertandingan pertama).
Jonathan Fingland
3
@JonathanFingland Anda salah paham - baca jawaban KevinDriedger lagi, bersama dengan konteks pertanyaan AlexanderV.Ilyin. Anda berdua memiliki arti yang sama.
kiedysktos
175

/bookstore/book[@location='US'][1] hanya bekerja dengan struktur sederhana.

Tambahkan sedikit lebih banyak struktur dan hal-hal istirahat.

Dengan

<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] hasil panen

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

bukan "simpul pertama yang cocok dengan kondisi yang lebih rumit". /bookstore/category/book[@location='US'][2]tidak mengembalikan apa pun.

Dengan tanda kurung Anda bisa mendapatkan hasil pertanyaan awal untuk:

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

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

dan (/bookstore/category/book[@location='US'])[2]bekerja seperti yang diharapkan.

tkurki
sumber
11
Penulis jawaban yang diterima di sini. Pertanyaan OP dianggap /bookstore/book[1]dan TIDAK (/bookstore/book)[1]. Kasing yang Anda berikan tidak sama dengan yang diminta OP. Agaknya, OP menerima jawaban saya karena melakukan apa yang dia harapkan (dan minta).
Jonathan Fingland
Jawaban ini diberikan membantu saya untuk kasus aneh ini. Dapatkah seseorang menjelaskan mengapa itu tidak akan menangani "situasi yang lebih rumit"? Karena pada dasarnya ia menemukan daftar dengan dua item, [2] harus mengambilnya (di duniaku)
Skurpi
Saya juga menemukan jawaban ini lebih benar daripada jawaban yang dipilih, seperti dalam kasus saya, saya juga memiliki struktur yang lebih kompleks di mana hanya menambahkan [1] kembali beberapa node. Terima kasih!
mydoghasworms
2
Kurung bekerja! Anda juga dapat menambahkan lebih banyak jalan setelah (..) [1], seperti: '(//div[text() = "'+ name +'"])[1]/following-sibling::*/div/text()'. Jika ada banyak node yang cocok name.
Hlung
1
Saya mengubah pendapat saya. Setelah agak jauh, saya mendapatkan apa yang dikatakan jawaban ini, dan jika saya tidak melihat contoh OP saya akan memilih ini. Saya kira saya bereaksi terhadap nada jawaban ini; jika @tkurki telah menjelaskan lebih banyak tentang memisahkan kondisi dari pemilihan node pertama, saya akan langsung melihatnya. Mungkin sama untuk JonFingland.
Gerard ONeill
51

Sebagai penjelasan atas jawaban Jonathan Fingland:

  • beberapa kondisi dalam predikat yang sama ( [position()=1 and @location='US']) harus benar secara keseluruhan
  • beberapa kondisi dalam predikat berurutan ( [position()=1][@location='US']) harus benar satu demi satu
  • ini menyiratkan bahwa [position()=1][@location='US']! = [@location='US'][position()=1]
    sementara [position()=1 and @location='US']==[@location='US' and position()=1]
  • petunjuk: satu [position()=1]dapat disingkat menjadi[1]

Anda dapat membangun ekspresi kompleks dalam predikat dengan operator Boolean " and" dan " or", dan dengan fungsi XPath Boolean not(), true()dan false(). Plus Anda dapat membungkus sub-ekspresi dalam tanda kurung.

Tomalak
sumber
15

Cara termudah untuk menemukan simpul buku bahasa Inggris pertama (dalam seluruh dokumen), dengan mempertimbangkan file xml yang terstruktur, seperti:

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

adalah ekspresi xpath:

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

Astaga
sumber
10
    <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> 

Jadi Mengingat hal di atas; Anda dapat memilih buku pertama dengan

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

Dan ini akan menemukan yang pertama di mana saja yang memiliki lokasi AS. [A1]

//book[@location='US']

Akan mengembalikan set simpul dengan semua buku dengan lokasi AS. [A1, B1, C2]

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

Akan mengembalikan lokasi buku pertama AS yang ada dalam kategori di mana saja dalam dokumen. [B1]

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

akan mengembalikan buku pertama dengan lokasi AS yang ada di mana saja di bawah toko buku elemen root; membuat bagian toko buku benar-benar berlebihan. [A1]

Dalam jawaban langsung:

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

Akan mengembalikan Anda simpul pertama untuk elemen buku dengan lokasi AS yang berada di bawah toko buku [A1]

Kebetulan jika Anda mau, dalam contoh ini untuk menemukan buku AS pertama yang bukan anak langsung dari toko buku:

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

Gunakan indeks untuk mendapatkan simpul yang diinginkan jika xpath rumit atau lebih dari satu simpul hadir dengan xpath yang sama.

Mis:

(//bookstore[@location = 'US'])[index]

Anda dapat memberikan nomor simpul mana yang Anda inginkan.

Mounika Medipelli
sumber
2

jika namespace disediakan pada xml yang diberikan, lebih baik menggunakan ini.

(/*[local-name() ='bookstore']/*[local-name()='book'][@location='US'])[1]
Ed Bangga
sumber
0

misalnya

<input b="demo">

Dan

(input[@b='demo'])[1]
SenthilKumarP
sumber
-1

Dengan bantuan tester xpath online, saya menulis jawaban ini ...
Untuk ini:

<table id="t2"><tbody>
<tr><td>123</td><td>other</td></tr>
<tr><td>foo</td><td>columns</td></tr>
<tr><td>bar</td><td>are</td></tr>
<tr><td>xyz</td><td>ignored</td></tr>
</tbody></table>

xpath berikut:

id("t2") / tbody / tr / td[1]

output:

123
foo
bar
xyz

Karena 1 berarti memilih semua elemen td yang merupakan anak pertama dari orang tua langsung mereka sendiri.
Tetapi xpath berikut:

(id("t2") / tbody / tr / td)[1]

output:

123
Mohsen Abasi
sumber