Permintaan XPath untuk mendapatkan instance elemen ke-n

135

Ada file HTML (yang isinya saya tidak kontrol) yang memiliki beberapa inputelemen semua dengan idatribut tetap yang sama "search_query". Isi file dapat berubah, tetapi saya tahu bahwa saya selalu ingin mendapatkan inputelemen kedua dengan atribut id "search_query".

Saya perlu ekspresi XPath untuk melakukan ini. Saya mencoba //input[@id="search_query"][2]tetapi itu tidak berhasil. Berikut adalah contoh string XML di mana kueri ini gagal:

<div>
  <form>
    <input id="search_query" />
   </form>
</div>

<div>
  <form>
    <input id="search_query" />
  </form>
</div>

<div>
  <form>
    <input id="search_query" />
  </form>
</div>

Perlu diingat bahwa di atas hanyalah sebuah contoh dan kode HTML lainnya dapat sangat berbeda dan inputelemen dapat muncul di mana saja tanpa struktur dokumen yang konsisten (kecuali bahwa saya dijamin akan selalu ada setidaknya dua inputelemen dengan atribut id dari "search_query").

Apa ekspresi XPath yang benar?

rlandster
sumber
Pertanyaan bagus, +1. Lihat jawaban saya untuk penjelasan lengkap tentang masalah dan untuk solusi yang diinginkan.
Dimitre Novatchev
7
Poin minor: Anda tidak boleh memiliki lebih dari satu elemen dengan ID yang diberikan (dan HTML dalam pertanyaan tersebut sebenarnya tidak valid). Dalam praktiknya, browser akan tetap membiarkan Anda melakukannya, tetapi jika Anda melakukannya, Anda kehilangan satu-satunya manfaat menggunakan ID, yaitu bahwa mereka memberi sinyal "Saya unik" (sedangkan kelas dirancang untuk digunakan untuk non- penanda unik).
machineghost

Jawaban:

244

Ini adalah FAQ :

//somexpression[$N]

berarti "Temukan setiap simpul yang dipilih oleh //somexpressionitu adalah $Nanak ke-2 dari induknya".

Yang Anda inginkan adalah :

(//input[@id="search_query"])[2]

Ingat : []Operator memiliki prioritas lebih tinggi (prioritas) daripada //singkatan.

Dimitre Novatchev
sumber
6
Saya suka jawaban ini. Saya tidak menganggap masalah yang diutamakan (saya hanya mengandaikan prioritas dari kiri ke kanan).
rlandster
10
@rlandster: Kata "presedensi" mungkin membingungkan. Bentuk //input[@id='search_query'][2]/descendat-or-self::node()/child::input[attribute::id='search_query'][position()=2]
21
Bagi mereka yang tiba di sini dari Google - penomoran dimulai dari 1 - [1] menjadi elemen pertama dan seterusnya
Jan Mares
Aneh bahwa dalam pertanyaan XPath ini array jenis ini mulai dengan 1, membingungkan saya.
Ivotje50
@ Ivotje50 Ya sekuens dan array XPath berbasis 1
Dimitre Novatchev
21

Ini sepertinya berhasil:

/descendant::input[@id="search_query"][2]

Saya menggunakan ini dari "Referensi Programmer XSLT 2.0 dan XPath 2.0, Edisi ke-4" oleh Michael Kay.

Ada juga catatan di bagian "Sintaks Singkat" dari spesifikasi Bahasa Jalur XML http://www.w3.org/TR/xpath/#path-abbrev yang memberikan petunjuk.

rlandster
sumber
Terima kasih banyak atas jawaban ini. Dalam kasus saya, solusi yang diterima tidak akan berfungsi karena saya menggunakan xpath dalam kerangka robot, yang tidak akan menerima jalur yang dimulai dengan tanda kurung. Namun yang ini, harus melakukan trik
dahui