Как выбрать указанный узел в наборах узлов Xpath по индексу с помощью Selenium?

92

Я пишу тестовый сценарий Selenium. А вот выражение xpath, которое я использую для сопоставления всех кнопок «Изменить» в таблице данных.

//img[@title='Modify']

У меня вопрос: как я могу посетить соответствующие наборы узлов по индексу? Я пробовал с

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

а также

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

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

Кимаир Ву
источник

Ответы:

194

Это FAQ :

//someName[3]

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

Вам нужен именно третий someNameэлемент :

(//someName)[3]

Объяснение : []имеет более высокий приоритет (приоритет), чем //. Не забывайте всегда помещать выражения типа //someNameв скобки, когда вам нужно указать N-й узел их выбранного списка узлов.

Димитр Новачев
источник
1
Спасибо! Извините, я совсем забыл о приоритетах ... Я просто попробовал, и это работает!
Kymair Wu
1
@ Kymair-Wu: Я рад, что этот ответ был вам полезен. Здесь, в SO, способ выразить благодарность - принять ответ (подсказка: щелкните галочку рядом с ответом). :)
Димитр Новачев
@DimitreNovatchev, вы снова и снова получаете баллы за один и тот же вопрос: p, спасибо за FAQ.
Eytoss
2
@Eytoss, пожалуйста. И да, я получаю больше всего +1 за относительно простые ответы - не за ответы, которые я считаю своими самыми большими достижениями - вероятно, потому что все понимают первое и почти никто не понимает второе :)
Димитр Новачев
2
@TEHEMPRAH, На самом деле я увидел, что в ответе я не сказал «3-й дочерний элемент someName его родителя». Спасибо, что заметили это. Исправлено сейчас.
Димитр Новачев 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]
Самир Агияр,
1
@kopranb Объяснение см. в этом ответе stackoverflow.com/a/1006439/18771
Tomalak
Спасибо за объяснение по поводу '// img [@ title =' Modify '] [' + i + ']' (+1)
DebanjanB
3

Нет iв xpath не совсем верно. Вы все еще можете использовать count()для поиска index.

Рассмотрим следующую страницу

<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кнопка в обеих таблицах.

Предполагая, что пользователь должен выбрать 4-ю 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

Эрик Стэнли
источник
большое спасибо! Я использую это, но я пришел к td[count(../preceding-sibling::tr/th[.='Heading 4'])]/following-sibling::tdтому, что не td[1]каждый раз попадаю в то, что у меня нет заголовка :)
mani
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дочернего элемента.
1

(// * [@ attribute = 'value']) [index], чтобы найти цель элемента, пока вы находите в нем несколько совпадений

Махеш
источник
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]
Шринивас Касса
источник