Menggunakan XPATH untuk menelusuri teks yang berisi & nbsp;

120

Saya menggunakan XPather Browser untuk memeriksa ekspresi XPATH saya di halaman HTML.

Tujuan akhir saya adalah menggunakan ekspresi ini di Selenium untuk pengujian antarmuka pengguna saya.

Saya mendapat file HTML dengan konten yang mirip dengan ini:

<tr>
  <td> abc </td>
  <td> & nbsp; </td>
</tr>

Saya ingin memilih node dengan teks yang berisi string "&nbsp; ".

Dengan string normal seperti "abc" tidak ada masalah. Saya menggunakan XPATH yang mirip dengan//td[text()="abc"] .

Ketika saya mencoba dengan XPATH seperti //td[text()="&nbsp;"]itu tidak menghasilkan apa-apa. Apakah ada aturan khusus tentang teks dengan " &"?

Bergeroy
sumber
Apakah transformasi XSL Anda yang sebenarnya tidak menghasilkan apa-apa? Atau hanya Xpather?
Zack The Human

Jawaban:

89

Tampaknya OpenQA , orang-orang di belakang Selenium, telah mengatasi masalah ini. Mereka mendefinisikan beberapa variabel agar sesuai dengan spasi putih. Dalam kasus saya, saya perlu menggunakan XPATH yang mirip dengan //td[text()="${nbsp}"].

Saya mereproduksi di sini teks dari OpenQA tentang masalah ini (ditemukan di sini ):

HTML secara otomatis menormalkan spasi dalam elemen, mengabaikan spasi di depan / di belakang dan mengubah spasi ekstra, tab, dan baris baru menjadi satu spasi. Saat Selenium membaca teks dari halaman, ia mencoba untuk menduplikasi perilaku ini, sehingga Anda dapat mengabaikan semua tab dan baris baru di HTML Anda dan melakukan pernyataan berdasarkan tampilan teks di browser saat ditampilkan. Kami melakukan ini dengan mengganti semua spasi yang tidak terlihat (termasuk spasi yang tidak putus " &nbsp;") dengan satu spasi. Semua baris baru yang terlihat ( <br>,, <p>dan <pre>baris baru yang diformat) harus dipertahankan.

Kami menggunakan logika normalisasi yang sama pada teks tabel kasus uji HTML Selenese. Ini memiliki sejumlah keuntungan. Pertama, Anda tidak perlu melihat sumber HTML halaman untuk mengetahui apa yang seharusnya menjadi pernyataan Anda; &nbsp;Simbol " " tidak terlihat oleh pengguna akhir, jadi Anda tidak perlu mengkhawatirkannya saat menulis pengujian Selenese. (Anda tidak perlu menempatkan &nbsp;penanda " " dalam kasus pengujian Anda untuk assertText pada bidang yang berisi " &nbsp;".) Anda juga dapat menambahkan baris dan spasi ekstra di <td>tag Selenese Anda ; karena kita menggunakan logika normalisasi yang sama pada kasus uji seperti yang kita lakukan pada teks, kita dapat memastikan bahwa pernyataan dan teks yang diekstrak akan sama persis.

Ini menciptakan sedikit masalah pada kesempatan langka tersebut ketika Anda benar-benar ingin / perlu memasukkan spasi ekstra dalam kasus pengujian Anda. Misalnya, Anda mungkin perlu mengetik teks di bidang seperti ini: " foo ". Tetapi jika Anda hanya menulis<td>foo </td> dalam kasus uji Selenese, kami akan mengganti spasi ekstra Anda hanya dengan satu spasi.

Masalah ini memiliki solusi sederhana. Kami telah menetapkan variabel dalam bahasa Selenese ${space}, yang nilainya berupa spasi tunggal. Anda dapat menggunakan ${space}untuk menyisipkan spasi yang tidak akan secara otomatis dipangkas, seperti ini: <td>foo${space}${space}${space}</td>. Kami juga menyertakan variabel ${nbsp} , yang dapat Anda gunakan untuk menyisipkan spasi non-breaking.

Perhatikan bahwa XPath tidak menormalkan spasi seperti yang kita lakukan. Jika Anda perlu menulis seperti XPath //div[text()="hello world"]tetapi HTML tautannya benar-benar " hello&nbsp;world", Anda harus memasukkan " &nbsp;" yang asli ke dalam kasus uji Selenese Anda agar cocok, seperti ini: //div[text()="hello${nbsp}world"] .

Bergeroy
sumber
1
Tautan OpenQA tidak lagi berhasil memuat
kjosh
1
Saya hanya ingin mencatat bahwa $ {nbsp} tidak berfungsi untuk saya di Selenium atau alat dev Chrome, juga tidak \u00a0. Yang berhasil bagi saya adalah mengetik spasi non-breaking, di mac Alt+Shift+Space. Pencarian web mengatakan Alt+0160di windows.
Sinis
25

Saya menemukan saya dapat membuat pertandingan ketika saya memasukkan spasi non-breaking hard-code (U + 00A0) dengan mengetik Alt + 0160 di Windows di antara dua tanda kutip ...

//table[@id='TableID']//td[text()=' ']

bekerja untuk saya dengan karakter khusus.

Dari apa yang saya pahami, standar XPath 1.0 tidak menangani karakter Unicode yang keluar. Sepertinya ada fungsi untuk itu di XPath 2.0 tetapi sepertinya Firefox tidak mendukungnya (atau saya salah paham). Jadi, Anda harus melakukan dengan codepage lokal. Jelek, saya tahu.

Sebenarnya, sepertinya standarnya mengandalkan bahasa pemrograman yang menggunakan XPath untuk memberikan urutan escape Unicode yang benar ... Jadi, entah bagaimana, saya melakukan hal yang benar.

PhiLho
sumber
Menggunakan Xpather 1.4.1 di Firefox 2, // td [text () = ''] tidak membuahkan hasil.
Zack The Human
Maaf. Itu tidak berhasil untuk saya. Tujuan akhir saya adalah menggunakannya di Selenium untuk pengujian antarmuka Web saya. Selenium sendiri menyimpan ekspresi tes dalam struktur XML dan pengetikan Alt Windows tampaknya tersesat. Juga, & # 160; kembali sebagai dalam XML.
Bergeroy
Zack, seperti yang saya tulis, Anda harus mengganti spasi di antara dua tanda kutip dengan karakter yang dihasilkan oleh Alt + 0160 (pada keypad numerik).
PhiLho
4
Harus mengerjakan ini dengan PHP dengan sukses juga:$col = $xpath->query("//p[text()=\"\xC2\xA0\"]");
hakre
@Bergory Ini bekerja menggunakan Busur derajat dengan driver Selenium
Damian Green
4

Coba gunakan entitas desimal, &#160;bukan entitas bernama. Jika itu tidak berhasil, Anda harus dapat menggunakan karakter unicode untuk spasi non-breaking daripada &nbsp;entitas.

(Catatan: Saya tidak mencoba ini di XPather, tetapi saya mencobanya di Oxygen.)

James Sulak
sumber
2

Ingatlah bahwa prosesor XML standar-compliant akan menggantikan entitas referensi lain dari lima yang standar XML ini ( &amp;, &gt;, &lt;, &apos;, &quot;) dengan yang sesuai karakter dalam pengkodean sasaran pada saat ekspresi XPath dievaluasi. Mengingat perilaku tersebut, saran PhiLho dan jsulak adalah cara yang tepat jika Anda ingin bekerja dengan alat XML. Saat Anda memasukkan &#160;ekspresi XPath, itu harus diubah ke urutan byte yang sesuai sebelum ekspresi XPath diterapkan.

ChuckB
sumber
1
Tidak jika Anda mencoba / menggunakan XPath di XPather (GUI) atau di JavaScript (tidak ada substitusi otomatis entitas, karena kami tidak dalam XML). Saran yang baik di lingkungan XML lain (XSTL?).
PhiLho
1

Saya tidak bisa mendapatkan kecocokan menggunakan Xpather, tetapi yang berikut ini berfungsi untuk saya dengan file XML dan XSL biasa di XML Notepad Microsoft:

<xsl:value-of select="count(//td[text()='&nbsp;'])" />

Nilai yang dikembalikan adalah 1, yang merupakan nilai yang benar dalam kasus uji saya.

Namun, saya harus mendeklarasikan nbsp sebagai entitas dalam XML dan XSL saya menggunakan yang berikut ini:

<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp "&#160;"> ]>

Saya tidak yakin apakah itu membantu Anda, tetapi saya dapat benar - benar menemukan nbsp menggunakan ekspresi XPath.

Sunting: Contoh kode saya sebenarnya berisi karakter '& nbsp;' tetapi sorotan sintaks JavaScript mengubahnya menjadi karakter spasi. Jangan menyesatkan!

Zack The Human
sumber
Anda dapat mengedit sampel kode Anda seperti yang dilakukan untuk sampel dalam pertanyaan saya. Ganti entitas nbsp Anda dengan & amp; nbsp ;.
Bergeroy
1

Cari &nbsp;atau hanya nbsp- apakah Anda mencoba ini?

Nakilon
sumber
Saya menyadari bahwa ini seharusnya berhasil tetapi tidak begitu yakin dengan apa yang saya temukan. Pasti ada cara di XPATH untuk menyandikan cara tertentu agar sesuai dengan apa yang saya cari.
Bergeroy
Mungkin saya harus melihat ke ekspresi reguler.
Bergeroy
1

Sesuai HTML yang telah Anda berikan:

<tr>
  <td>abc</td>
  <td>&nbsp;</td>
</tr>

Untuk menemukan node dengan string &nbsp;Anda dapat menggunakan salah satu dari berikut ini solusi berbasis:

  • Menggunakan text():

    "//td[text()='\u00A0']"
  • Menggunakan contains():

    "//td[contains(., '\u00A0')]"

Namun, idealnya Anda mungkin ingin menghindari karakter NO-BREAK SPACE dan menggunakan salah satu Strategi Penunjuk Lokasi berikut :

  • Menggunakan <tr>node induk dan following-sibling:

    "//tr//following-sibling::td[2]"
  • Menggunakan starts-with():

    "//tr//td[last()]"
  • Menggunakan <td>node sebelumnya danfollowingnode and following-sibling`:

    "//td[text()='abc']//following::td[1]"

Referensi

Anda dapat menemukan pembahasan rinci yang relevan di:


tl; dr

Karakter Unicode 'NO-BREAK SPACE' (U + 00A0)

DebanjanB
sumber