Bagaimana cara memilih node yang ditentukan dalam set node Xpath dengan indeks dengan Selenium?

92

Saya sedang menulis testcase Selenium. Dan inilah ekspresi xpath yang saya gunakan untuk mencocokkan semua tombol 'Ubah' dalam tabel data.

//img[@title='Modify']

Pertanyaan saya adalah, bagaimana saya bisa mengunjungi kumpulan node yang cocok dengan indeks? Saya sudah mencoba dengan

//img[@title='Modify'][i]

dan

//img[@title='Modify' and position() = i]

Tapi tidak ada yang berhasil .. Saya juga mencoba dengan pemeriksa XPath (Satu ekstensi firefox). Ada total 13 kecocokan yang ditemukan, maka saya sama sekali tidak tahu bagaimana saya akan memilih salah satunya .. Atau apakah XPath mendukung pemilihan node tertentu yang tidak berada di bawah node induk yang sama?

Kymair Wu
sumber

Jawaban:

194

Ini adalah FAQ :

//someName[3]

artinya : semua someNameelemen dalam dokumen, yang merupakan someNameanak ketiga dari induknya - mungkin ada banyak elemen seperti itu.

Yang Anda inginkan adalah someNameelemen ke-3 :

(//someName)[3]

Penjelasan : yang []memiliki prioritas (prioritas) lebih tinggi daripada //. Ingatlah selalu untuk meletakkan ekspresi tipe //someNamedalam tanda kurung ketika Anda perlu menentukan node ke-N dari daftar node yang mereka pilih.

Dimitre Novatchev
sumber
1
Terima kasih banyak! Maaf saya benar-benar lupa hal-hal yang diutamakan .. Saya baru saja mencoba dan berhasil!
Kymair Wu
1
@ Kymair-Wu: Saya senang jawaban ini bermanfaat bagi Anda. Di sini, di SO cara mengungkapkan rasa syukur adalah dengan menerima jawaban (petunjuk: klik tanda centang di sebelah jawaban). :)
Dimitre Novatchev
@DimitreNovatchev Anda mendapatkan poin untuk pertanyaan yang sama berulang kali: p, terima kasih untuk FAQ.
Eytoss
2
@Eytoss, sama-sama. Dan ya, saya mendapatkan paling banyak +1 untuk jawaban yang relatif sederhana - bukan untuk jawaban yang saya yakini sebagai pencapaian terbesar saya - mungkin karena semua orang memahami yang pertama dan hampir tidak ada yang memahami yang terakhir :)
Dimitre Novatchev
2
@TEHEMPRAH, Sebenarnya saya melihat bahwa dalam jawaban saya tidak mengatakan "anak 'someName' ke-3 dari orang tuanya". Terima kasih telah memperhatikan ini. Dikoreksi sekarang.
Dimitre Novatchev
14

Tidak ada idi XPath.

Entah Anda menggunakan angka literal: //img[@title='Modify'][1]

Atau Anda membangun string ekspresi secara dinamis: '//img[@title='Modify']['+i+']'(namun perlu diingat bahwa ekspresi XPath dinamis tidak berfungsi dari dalam XSLT).

Atau apakah XPath mendukung pemilihan node tertentu yang tidak berada di bawah node induk yang sama?

Iya: (//img[@title='Modify'])[13]


Ini //img[@title='Modify'][i]berarti "apa saja <img>dengan judul 'Ubah' dan elemen anak bernama <i>."

Tomalak
sumber
Untuk beberapa alasan saya perlu memasukkan indeks sebelum ekspresi atribut. Misalnya, untuk menemukan tdanak keenam dari a trdan tidak memiliki konten kosong://tr/td[6][string-length(text()) > 0]
Samir Aguiar
1
@kopranb Untuk penjelasan, lihat jawaban ini stackoverflow.com/a/1006439/18771
Tomalak
Terima kasih telah menjelaskan tentang '// img [@ title =' Modify '] [' + i + ']' (+1)
DebanjanB
3

Tidak ada idi xpath tidak sepenuhnya benar. Anda masih dapat menggunakan count()untuk menemukan indeks.

Simak halaman berikut ini

<html>

	<head>
		<title>HTML Sample table</title>
	</head>

	<style>
	table, td, th {
		border: 1px solid black;
		font-size: 15px;
		font-family: Trebuchet MS, sans-serif;
	}
	table {
		border-collapse: collapse;
		width: 100%;
	}

	th, td {
		text-align: left;
		padding: 8px;
	}

	tr:nth-child(even){background-color: #f2f2f2}

	th {
		background-color: #4CAF50;
		color: white;
	}
	</style>

	<body>
	<table>
		<thead>
			<tr>
				<th>Heading 1</th>
				<th>Heading 2</th>
				<th>Heading 3</th>
				<th>Heading 4</th>
				<th>Heading 5</th>
				<th>Heading 6</th>
			</tr>
		</thead>
		<tbody>
			<tr>
				<td>Data row 1 col 1</td>
				<td>Data row 1 col 2</td>
				<td>Data row 1 col 3</td>
				<td>Data row 1 col 4</td>
				<td>Data row 1 col 5</td>
				<td>Data row 1 col 6</td>
			</tr>
			<tr>
				<td>Data row 2 col 1</td>
				<td>Data row 2 col 2</td>
				<td>Data row 2 col 3</td>
				<td>Data row 2 col 4</td>
				<td>Data row 2 col 5</td>
				<td>Data row 2 col 6</td>
			</tr>
			<tr>
				<td>Data row 3 col 1</td>
				<td>Data row 3 col 2</td>
				<td>Data row 3 col 3</td>
				<td>Data row 3 col 4</td>
				<td>Data row 3 col 5</td>
				<td>Data row 3 col 6</td>
			</tr>
			<tr>
				<td>Data row 4 col 1</td>
				<td>Data row 4 col 2</td>
				<td>Data row 4 col 3</td>
				<td>Data row 4 col 4</td>
				<td>Data row 4 col 5</td>
				<td>Data row 4 col 6</td>
			</tr>
			<tr>
				<td>Data row 5 col 1</td>
				<td>Data row 5 col 2</td>
				<td>Data row 5 col 3</td>
				<td>Data row 5 col 4</td>
				<td>Data row 5 col 5</td>
				<td>Data row 5 col 6</td>
			</tr>
			<tr>
				<td><button>Modify</button></td>
				<td><button>Modify</button></td>
				<td><button>Modify</button></td>
				<td><button>Modify</button></td>
				<td><button>Modify</button></td>
				<td><button>Modify</button></td>
			</tr>
		</tbody>
	</table>

	</br>

	<table>
		<thead>
			<tr>
				<th>Heading 7</th>
				<th>Heading 8</th>
				<th>Heading 9</th>
				<th>Heading 10</th>
				<th>Heading 11</th>
				<th>Heading 12</th>
			</tr>
		</thead>
		<tbody>
			<tr>
				<td>Data row 1 col 1</td>
				<td>Data row 1 col 2</td>
				<td>Data row 1 col 3</td>
				<td>Data row 1 col 4</td>
				<td>Data row 1 col 5</td>
				<td>Data row 1 col 6</td>
			</tr>
			<tr>
				<td>Data row 2 col 1</td>
				<td>Data row 2 col 2</td>
				<td>Data row 2 col 3</td>
				<td>Data row 2 col 4</td>
				<td>Data row 2 col 5</td>
				<td>Data row 2 col 6</td>
			</tr>
			<tr>
				<td>Data row 3 col 1</td>
				<td>Data row 3 col 2</td>
				<td>Data row 3 col 3</td>
				<td>Data row 3 col 4</td>
				<td>Data row 3 col 5</td>
				<td>Data row 3 col 6</td>
			</tr>
			<tr>
				<td>Data row 4 col 1</td>
				<td>Data row 4 col 2</td>
				<td>Data row 4 col 3</td>
				<td>Data row 4 col 4</td>
				<td>Data row 4 col 5</td>
				<td>Data row 4 col 6</td>
			</tr>
			<tr>
				<td>Data row 5 col 1</td>
				<td>Data row 5 col 2</td>
				<td>Data row 5 col 3</td>
				<td>Data row 5 col 4</td>
				<td>Data row 5 col 5</td>
				<td>Data row 5 col 6</td>
			</tr>
			<tr>
				<td><button>Modify</button></td>
				<td><button>Modify</button></td>
				<td><button>Modify</button></td>
				<td><button>Modify</button></td>
				<td><button>Modify</button></td>
				<td><button>Modify</button></td>
			</tr>
		</tbody>
	</table>

	</body>
</html>

Halaman ini memiliki 2 tabel dan memiliki 6 kolom masing-masing dengan nama kolom unik dan 6 baris dengan data variabel. Baris terakhir memiliki Modifytombol di kedua tabel.

Dengan asumsi bahwa pengguna harus memilih Modifytombol ke-4 dari tabel pertama berdasarkan judulnya

Gunakan xpath //th[.='Heading 4']/ancestor::thead/following-sibling::tbody/tr/td[count(//tr/th[.='Heading 4']/preceding-sibling::th)+1]/button

The count()Operator berguna dalam situasi seperti ini.

Logika:

  1. Temukan header untuk Modifymenggunakan tombol//th[.='Heading 4']
  2. Temukan indeks kolom tajuk menggunakan count(//tr/th[.='Heading 4']/preceding-sibling::th)+1

Catatan: Indeks dimulai pada0

  1. Dapatkan baris untuk tajuk yang sesuai menggunakan //th[.='Heading 4']/ancestor::thead/following-sibling::tbody/tr/td[count(//tr/th[.='Heading 4']/preceding-sibling::th)+1]

  2. Dapatkan Modifytombol dari daftar node yang diekstrak menggunakan//th[.='Heading 4']/ancestor::thead/following-sibling::tbody/tr/td[count(//tr/th[.='Heading 4']/preceding-sibling::th)+1]/button

Eric Stanley
sumber
Terima kasih banyak! saya menggunakannya, tetapi saya sampai pada td[count(../preceding-sibling::tr/th[.='Heading 4'])]/following-sibling::tdhal itu tidak jatuh ke td[1]setiap kali saya tidak memiliki beberapa judul :)
mani
2
//img[@title='Modify'][i]

adalah kependekan dari

/descendant-or-self::node()/img[@title='Modify'][i]

karenanya mengembalikan simpul ke-i di bawah simpul induk yang sama.

Kamu ingin

/descendant-or-self::img[@title='Modify'][i]
Nick Jones
sumber
1
Hanya /descendant::img[@title='Modify'][$index]akan bekerja dengan baik. Perhatikan juga bahwa [i]tes predikat untuk keberadaan ielemen anak.
1

(// * [@ attribute = 'value']) [index] untuk menemukan target elemen sementara Anda menemukan beberapa kecocokan di dalamnya

mahesh
sumber
1
Bisakah Anda menjelaskan lebih banyak?
abhiarora
0

Berikut adalah solusi untuk variabel indeks

Misalkan, Anda telah menemukan 5 elemen dengan pelacak yang sama dan Anda ingin melakukan tindakan pada setiap elemen dengan memberikan nomor indeks (di sini, variabel digunakan untuk indeks sebagai "i")

for(int i=1; i<=5; i++)
{
    string xPathWithVariable = "(//div[@class='className'])" + "[" + i + "]";
    driver.FindElement(By.XPath(xPathWithVariable)).Click();
}

Dibutuhkan XPath:

(//div[@class='className'])[1]
(//div[@class='className'])[2]
(//div[@class='className'])[3]
(//div[@class='className'])[4]
(//div[@class='className'])[5]
Srinivas Kassa
sumber