Як вибрати вказаний вузол у наборах вузлів Xpath за індексом за допомогою Selenium?


91

Я пишу тест-кейс для селену. І ось вираз xpath, який я використовую для зіставлення всіх кнопок «Змінити» в таблиці даних.

//img[@title='Modify']

Моє питання полягає в тому, як я можу відвідати відповідні набори вузлів за індексом? Я пробував з

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

і

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

Але ні те, ні інше не працює .. Я також спробував перевірити XPath (одне розширення firefox). Всього знайдено 13 збігів, тоді я абсолютно не уявляю, як вибрати один із них .. Або XPath підтримує вказаний вибір вузлів, які не знаходяться під одним батьківським вузлом?

Відповіді:


190

Це FAQ :

//someName[3]

означає : усі someNameелементи в документі, які є третьою someNameдочірньою структурою їх батьків, - таких елементів може бути багато.

Те, що ви хочете - це саме 3-й someNameелемент :

(//someName)[3]

Пояснення : the []має вищий пріоритет (пріоритет), ніж //. Пам’ятайте, завжди слід вводити вирази типу //someNameв дужки, коли потрібно вказати N-й вузол у вибраному списку вузлів.


1
Дуже дякую! Вибачте, я повністю забув першочергові речі .. Я просто спробував, і це працює!
Kymair Wu,

1
@ Kymair-Wu: Я рада, що ця відповідь була для вас корисною. Тут у SO спосіб висловити вдячність - прийняти відповідь (підказка: клацніть галочку біля відповіді). :)
Dimitre Novatchev

@DimitreNovatchev ти знову і знову отримуєш бали за одне і те ж питання: p, дякую за поширені запитання.
Eytoss

2
@Eytoss, ласкаво просимо. І так, я отримую більшість оцінок +1 за відносно прості відповіді - не за відповіді, які, на мою думку, є моїми найбільшими досягненнями - можливо, тому, що всі розуміють перше, а майже ніхто не розуміє друге :)
Dimitre Novatchev

2
@TEHEMPRAH, Насправді я бачив, що у відповіді я не сказав "3-й дочірній матерія" someName "свого батька". Дякуємо, що помітили це. Зараз виправлено.
Dimitre Novatchev 02

14

У iXPath немає .

Або ви використовуєте буквальні числа: //img[@title='Modify'][1]

Або ви будуєте рядок вираження динамічно: '//img[@title='Modify']['+i+']'(але майте на увазі , що динамічні вирази XPath не працюють з в XSLT).

Або XPath підтримує вказаний вибір вузлів, які не знаходяться під одним батьківським вузлом?

Так: (//img[@title='Modify'])[13]


Це //img[@title='Modify'][i]означає "будь-який <img>із заголовком" Змінити "та дочірнім елементом з іменем <i>."


З якоїсь причини мені потрібно було включити індекс перед виразом атрибута. Наприклад, щоб знайти tds, які були шостою дитиною a trі не мають порожнього вмісту://tr/td[6][string-length(text()) > 0]
Samir Aguiar

1
@kopranb Для пояснення см цієї відповіді stackoverflow.com/a/1006439/18771
Томалак

Дякуємо за пояснення щодо '// img [@ title =' Modify '] [' + i + ']' (+1)
DebanjanB,

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

це скорочення від

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

отже, повертає i-й вузол під тим самим батьківським вузлом.

Ти хочеш

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

1
Просто /descendant::img[@title='Modify'][$index]буде працювати нормально. Також зверніть увагу, що [i]предикатний тест на наявність iдочірнього елемента.

2

Немає iв xpath не зовсім правдиво. Ви все ще можете використовувати count()індекс для пошуку індексу.

Розглянемо наступну сторінку

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

Сторінка має 2 таблиці та 6 стовпців, кожна з унікальними назвами стовпців та 6 рядків із змінними даними. В останньому рядку є Modifyкнопка в обох таблицях.

Припускаючи, що користувач повинен вибрати четверту Modifyкнопку з першої таблиці на основі заголовка

Використовуйте xpath //th[.='Heading 4']/ancestor::thead/following-sibling::tbody/tr/td[count(//tr/th[.='Heading 4']/preceding-sibling::th)+1]/button

count()Оператор знадобиться в подібних ситуаціях.

Логіка:

  1. Знайдіть заголовок Modifyкнопки за допомогою//th[.='Heading 4']
  2. Знайдіть індекс стовпця заголовка за допомогою count(//tr/th[.='Heading 4']/preceding-sibling::th)+1

Примітка: Індекс починається з0

  1. Отримайте рядки для відповідного заголовка за допомогою //th[.='Heading 4']/ancestor::thead/following-sibling::tbody/tr/td[count(//tr/th[.='Heading 4']/preceding-sibling::th)+1]

  2. Отримайте Modifyкнопку зі списку вилучених вузлів за допомогою//th[.='Heading 4']/ancestor::thead/following-sibling::tbody/tr/td[count(//tr/th[.='Heading 4']/preceding-sibling::th)+1]/button


1

(// * [@ attribute = 'value']) [індекс], щоб знайти ціль елемента, поки ви знаходите в ньому кілька збігів


1
Ви можете пояснити трохи більше?
abhiarora

0

Ось рішення для змінної індексу

Скажімо, ви знайшли 5 елементів з однаковим локатором, і ви хотіли б виконати дію з кожним елементом, вказавши номер індексу (тут змінна використовується для індексу як "i")

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

Для цього потрібен XPath:

(//div[@class='className'])[1]
(//div[@class='className'])[2]
(//div[@class='className'])[3]
(//div[@class='className'])[4]
(//div[@class='className'])[5]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.