Como selecionar o nó especificado dentro dos conjuntos de nós Xpath por índice com Selenium?


91

Estou escrevendo um caso de teste do Selenium. E aqui está a expressão xpath que uso para corresponder a todos os botões 'Modify' em uma tabela de dados.

//img[@title='Modify']

Minha pergunta é: como posso visitar os conjuntos de nós correspondentes por índice? Eu tentei com

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

e

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

Mas nem funciona .. Eu também tentei com o XPath checker (uma extensão do firefox). Há no total 13 correspondências encontradas, então não tenho a menor idéia de como vou selecionar uma delas. Ou o XPath oferece suporte à seleção especificada de nós que não estão no mesmo nó pai?

Respostas:


191

Este é um FAQ :

//someName[3]

significa : todos os someNameelementos no documento, que são o terceiro someNamefilho de seu pai - pode haver muitos desses elementos.

O que você quer é exatamente o terceiro someNameelemento :

(//someName)[3]

Explicação : o []tem uma precedência (prioridade) maior do que //. Lembre-se sempre de colocar as expressões do tipo //someNameentre colchetes quando precisar especificar o enésimo nó de sua lista de nós selecionada.


1
Muito obrigado! Desculpe, esqueci totalmente as coisas de precedência .. Acabei de experimentar e funciona!
— Kymair Wu

1
@ Kymair-Wu: Fico feliz que essa resposta tenha sido útil para você. Aqui no SO a forma de agradecer é aceitando uma resposta (dica: clique na marca de seleção ao lado da resposta). :)
— Dimitre Novatchev

@DimitreNovatchev você está recebendo pontos pela mesma pergunta repetidamente: p, obrigado pelo FAQ.
— Eytoss

2
@Eytoss, de nada. E sim, estou recebendo mais + 1s para respostas relativamente simples - não para as respostas que acredito serem minhas maiores conquistas - provavelmente porque todo mundo entende a primeira e quase ninguém entende a última :)
— Dimitre Novatchev

2
@TEHEMPRAH, Na verdade eu vi que na resposta não disse "o terceiro 'someName' filho de seu pai". Obrigado por perceber isso. Corrigido agora.
— Dimitre Novatchev,

14

Não existe ino XPath.

Ou você usa números literais: //img[@title='Modify'][1]

Ou você constrói a string de expressão dinamicamente: '//img[@title='Modify']['+i+']'(mas lembre-se de que as expressões XPath dinâmicas não funcionam dentro do XSLT).

Ou o XPath oferece suporte à seleção especificada de nós que não estão no mesmo nó pai?

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


Isso //img[@title='Modify'][i]significa "qualquer <img>um com o título 'Modificar' e um elemento filho chamado <i>".


Por algum motivo, precisei incluir o índice antes da expressão do atributo. Por exemplo, para encontrar tds que foram o sexto filho de a tre não têm conteúdo vazio://tr/td[6][string-length(text()) > 0]
— Samir Aguiar

1
@kopranb Para obter uma explicação, consulte esta resposta stackoverflow.com/a/1006439/18771
— Tomalak

Obrigado por explicar sobre '// img [@ title =' Modify '] [' + i + ']' (+1)
— DebanjanB

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

é curto para

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

portanto, está retornando o i'ésimo nó sob o mesmo nó pai.

Você quer

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

1
Só /descendant::img[@title='Modify'][$index]vai funcionar bem. Observe também que o [i]teste de predicado para a existência de ielemento filho.

2

Não há ino xpath não é totalmente verdade. Você ainda pode usar o count()para localizar o índice.

Considere a seguinte página

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

A página possui 2 tabelas e 6 colunas, cada uma com nomes de coluna exclusivos e 6 linhas com dados variáveis. A última linha contém o Modifybotão em ambas as tabelas.

Supondo que o usuário tenha que selecionar o 4º Modifybotão da primeira tabela com base no título

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

O count()operador é útil em situações como essas.

Lógica:

  1. Encontre o cabeçalho do Modifybotão usando//th[.='Heading 4']
  2. Encontre o índice da coluna do cabeçalho usando count(//tr/th[.='Heading 4']/preceding-sibling::th)+1

Nota: o índice começa em0

  1. Obtenha as linhas para o cabeçalho correspondente usando //th[.='Heading 4']/ancestor::thead/following-sibling::tbody/tr/td[count(//tr/th[.='Heading 4']/preceding-sibling::th)+1]

  2. Obtenha o Modifybotão da lista de nós extraída usando//th[.='Heading 4']/ancestor::thead/following-sibling::tbody/tr/td[count(//tr/th[.='Heading 4']/preceding-sibling::th)+1]/button


1

(// * [@ attribute = 'value']) [index] para encontrar o destino do elemento enquanto você encontra várias correspondências nele


1
Você pode explicar um pouco mais?
— abhiarora

0

Aqui está a solução para a variável de índice

Digamos que você encontrou 5 elementos com o mesmo localizador e gostaria de realizar uma ação em cada elemento, fornecendo o número do índice (aqui, a variável é usada para o índice como "i")

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

Leva XPath:

(//div[@class='className'])[1]
(//div[@class='className'])[2]
(//div[@class='className'])[3]
(//div[@class='className'])[4]
(//div[@class='className'])[5]
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.