Kasus tidak sensitif XPath berisi () mungkin?

94

Saya menjalankan semua textnode DOM saya dan memeriksa apakah nodeValue berisi string tertentu.

/html/body//text()[contains(.,'test')]

Ini peka huruf besar / kecil. Namun, saya juga ingin menangkap Test, TESTatau TesT. Apakah itu mungkin dengan XPath (dalam JavaScript)?

Aron Woost
sumber

Jawaban:

112

Ini untuk XPath 1.0. Jika lingkungan Anda mendukung XPath 2.0, lihat di sini .


Iya. Mungkin, tapi tidak cantik.

/html/body//text()[
  contains(
    translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),
    'test'
  )
]

Ini akan berfungsi untuk string pencarian di mana alfabet diketahui sebelumnya. Tambahkan karakter beraksen yang ingin Anda lihat.


Jika Anda bisa, tandai teks yang Anda minati dengan cara lain, seperti melampirkannya di dalam <span>yang memiliki kelas tertentu saat membangun HTML. Hal semacam itu jauh lebih mudah ditemukan dengan XPath daripada substring dalam teks elemen.

Jika itu bukan pilihan, Anda dapat mengizinkan JavaScript (atau bahasa host lain yang Anda gunakan untuk menjalankan XPath) membantu Anda membuat ekspresi XPath dinamis:

function xpathPrepare(xpath, searchString) {
  return xpath.replace("$u", searchString.toUpperCase())
              .replace("$l", searchString.toLowerCase())
              .replace("$s", searchString.toLowerCase());
}

xp = xpathPrepare("//text()[contains(translate(., '$u', '$l'), '$s')]", "Test");
// -> "//text()[contains(translate(., 'TEST', 'test'), 'test')]"

(Tip tip untuk jawaban @ KirillPolishchuk - tentu saja Anda hanya perlu menerjemahkan karakter yang sebenarnya Anda cari .)

Pendekatan ini akan bekerja untuk string pencarian apa pun, tanpa memerlukan pengetahuan sebelumnya tentang alfabet, yang merupakan nilai tambah yang besar.

Kedua metode di atas gagal ketika string pencarian dapat berisi tanda kutip tunggal, dalam hal ini segalanya menjadi lebih rumit .

Tomalak
sumber
Terima kasih! Juga tambahannya bagus, hanya menerjemahkan karakter yang dibutuhkan. Saya ingin tahu apa kemenangan kinerja itu. Perhatikan bahwa xpathPrepare () dapat menangani karakter yang muncul lebih dari sekali secara berbeda (misalnya Anda mendapatkan TEEEEEST dan teeeeest).
Aron Woost
@AronWoost: Ya, mungkin ada beberapa keuntungan, cukup bandingkan jika Anda ingin mengetahuinya. translate()sendiri tidak peduli seberapa sering Anda mengulangi setiap karakter - translate(., 'EE', 'ee')benar-benar setara translate(., 'E', 'e'). PS: Jangan lupa untuk memberikan suara positif kepada @KirPolishchuk, idenya adalah miliknya.
Tomalak
2
System.
Stefan Steiger
1
Tidak. Lihat bagian "tentu saja Anda hanya perlu menerjemahkan karakter yang sebenarnya Anda cari" .
Tomalak
62

Lebih indah:

/html/body//text()[contains(translate(., 'TES', 'tes'), 'test')]
Kirill Polishchuk
sumber
4
+1 Benar-benar. Itu adalah sesuatu yang tidak saya pikirkan. (Saya akan menggunakannya dalam jawaban saya, ini jauh lebih baik daripada rutinitas JavaScript asli yang saya tulis)
Tomalak
4
akan tidak hanya mengkonversi TESTke testdan cuti Testseperti itu?
Muhammad Adeel Zahid
7
@MuhammadAdeelZahid - Tidak, ini menggantikan "T" dengan "t", "E" dengan "e", dll. Ini adalah pertandingan 1-to-1.
Daniel Haley
Mungkin lebih jelas untuk dilakukan translate(., 'TES', 'tes'). Dengan begitu orang akan menyadari bahwa ini bukanlah terjemahan kata, melainkan terjemahan surat.
mlissner
atau 'EST,' est ', meskipun terlihat keren (meskipun agak samar) bahwa bagian dari istilah yang dicari muncul di pemetaan (huruf yang berulang dihapus)
George Birbilis
56

Solusi XPath 2.0

  1. Gunakan huruf kecil () :

    /html/body//text()[contains(lower-case(.),'test')]

  2. Gunakan pencocokan ekspresi reguler kecocokan () dengan panji tidak peka huruf besar / kecil:

    /html/body//text()[matches(.,'test', 'i')]

kjhughes
sumber
1
Apakah sintaks ini tidak didukung di Firefox dan Chrome? Saya baru saja mencobanya di konsol dan keduanya mengembalikan kesalahan sintaksis.
db
1
Firefox dan Chrome hanya menerapkan XPath 1.0.
kjhughes
di mana saya dapat memverifikasi bahwa ini akan berfungsi seperti yang diharapkan?
Ankit Gupta
@AnkitGupta: Alat online atau offline apa pun yang mendukung XPath 2.0 dapat digunakan untuk memverifikasi jawaban ini, tentu saja, tetapi (1) rekomendasi alat di luar topik di sini di SO dan (2) mengingat 56 suara positif, 0 suara negatif, dan tidak perbedaan pendapat selama lebih dari enam tahun, Anda dapat yakin bahwa jawaban ini benar. ;-)
kjhughes
8

Iya. Anda dapat menggunakan translateuntuk mengonversi teks yang ingin Anda cocokkan menjadi huruf kecil sebagai berikut:

/html/body//text()[contains(translate(., 
                                      'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
                                      'abcdefghijklmnopqrstuvwxyz'),
                   'test')]
Andy
sumber
6

Jika Anda menggunakan XPath 2.0 maka Anda dapat menentukan pemeriksaan sebagai argumen ketiga untuk mengandung (). Namun, URI pemeriksaan tidak distandarisasi sehingga detailnya bergantung pada produk yang Anda gunakan.

Perhatikan bahwa solusi yang diberikan sebelumnya menggunakan translate () semua mengasumsikan bahwa Anda hanya menggunakan alfabet bahasa Inggris 26 huruf.

UPDATE: XPath 3.1 mendefinisikan URI pemeriksaan standar untuk pencocokan buta huruf.

Michael Kay
sumber
3

Cara saya selalu melakukan ini adalah dengan menggunakan fungsi "terjemahkan" di XPath. Saya tidak akan mengatakan itu sangat cantik tetapi berfungsi dengan benar.

/html/body//text()[contains(translate(.,'abcdefghijklmnopqrstuvwxyz',
                                        'ABCDEFGHIJKLOMNOPQRSTUVWXYZ'),'TEST')]

semoga ini membantu,

Marvin Smit
sumber