Come selezionare il nodo specificato all'interno dei set di nodi Xpath per indice con Selenium?


91

Sto scrivendo un testcase sul selenio. Ed ecco l'espressione xpath che uso per abbinare tutti i pulsanti "Modifica" all'interno di una tabella dati.

//img[@title='Modify']

La mia domanda è: come posso visitare i set di nodi corrispondenti per indice? Ho provato con

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

e

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

Ma nessuno dei due funziona .. Ho provato anche con XPath checker (un'estensione per Firefox). Sono state trovate totalmente 13 corrispondenze, quindi non ho assolutamente idea di come selezionerò una di esse .. O XPath supporta la selezione specificata di nodi che non sono sotto lo stesso nodo genitore?

Risposte:


191

Questa è una FAQ :

//someName[3]

significa : tutti gli someNameelementi nel documento, che sono il terzo someNamefiglio del loro genitore - potrebbero esserci molti di questi elementi.

Quello che vuoi è esattamente il 3 ° someNameelemento :

(//someName)[3]

Spiegazione : []ha una precedenza (priorità) maggiore di //. Ricordarsi sempre di mettere le espressioni del tipo //someNametra parentesi quando è necessario specificare l'ennesimo nodo della loro lista di nodi selezionata.


1
Grazie mille! Scusa ho completamente dimenticato le cose precedenti .. Ho appena provato e funziona!
Kymair Wu

1
@ Kymair-Wu: sono contento che questa risposta ti sia stata utile. Qui a SO il modo di esprimere gratitudine è accettare una risposta (suggerimento: fare clic sul segno di spunta accanto alla risposta). :)
Dimitre Novatchev

@DimitreNovatchev stai ottenendo punti per la stessa domanda più e più volte: p, grazie per le FAQ.
Eytoss

2
@Eytoss, sei il benvenuto. E sì, ricevo la maggior parte dei +1 per risposte relativamente semplici - non per le risposte che credo siano i miei più grandi risultati - probabilmente perché tutti capiscono il primo e quasi nessuno capisce il secondo :)
Dimitre Novatchev

2
@TEHEMPRAH, In realtà ho visto che nella risposta non ho detto "il terzo figlio 'someName' del suo genitore". Grazie per averlo notato. Corretto ora.
Dimitre Novatchev

14

Non c'è iin XPath.

O usi numeri letterali: //img[@title='Modify'][1]

Oppure si crea la stringa dell'espressione in modo dinamico: '//img[@title='Modify']['+i+']'(ma si tenga presente che le espressioni XPath dinamiche non funzionano dall'interno di XSLT).

Oppure XPath supporta la selezione specificata di nodi che non si trovano sotto lo stesso nodo padre?

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


Ciò //img[@title='Modify'][i]significa "qualsiasi <img>con un titolo di" Modifica "e un elemento figlio denominato <i>".


Per qualche motivo avevo bisogno di includere l'indice prima dell'espressione dell'attributo. Ad esempio, per trovare messaggi di posta tdelettronica che erano il sesto figlio di a tre non hanno un contenuto vuoto://tr/td[6][string-length(text()) > 0]
Samir Aguiar,

1
@kopranb Per una spiegazione, vedere questa risposta stackoverflow.com/a/1006439/18771
Tomalak

Grazie per aver spiegato di '// img [@ title =' Modify '] [' + i + ']' (+1)
DebanjanB

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

è l'abbreviazione di

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

quindi sta restituendo l'i-esimo nodo sotto lo stesso nodo genitore.

Tu vuoi

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

1
Funzionerà /descendant::img[@title='Modify'][$index]bene. Notare anche che il [i]predicato verifica l'esistenza idell'elemento figlio.

2

Non c'è iin xpath non è del tutto vero. Puoi ancora usare count()per trovare l'indice.

Considera la pagina seguente

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

La pagina ha 2 tabelle e 6 colonne ciascuna con nomi di colonna univoci e 6 righe con dati variabili. L'ultima riga ha il Modifypulsante in entrambe le tabelle.

Supponendo che l'utente debba selezionare il 4 ° Modifypulsante dalla prima tabella in base all'intestazione

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

L' count()operatore torna utile in situazioni come queste.

Logica:

  1. Trova l'intestazione del Modifypulsante usando//th[.='Heading 4']
  2. Trova l'indice della colonna dell'intestazione utilizzando count(//tr/th[.='Heading 4']/preceding-sibling::th)+1

Nota: l' indice inizia da0

  1. Ottieni le righe per l'intestazione corrispondente utilizzando //th[.='Heading 4']/ancestor::thead/following-sibling::tbody/tr/td[count(//tr/th[.='Heading 4']/preceding-sibling::th)+1]

  2. Ottieni il Modifypulsante dall'elenco dei nodi estratti utilizzando//th[.='Heading 4']/ancestor::thead/following-sibling::tbody/tr/td[count(//tr/th[.='Heading 4']/preceding-sibling::th)+1]/button


1

(// * [@ attribute = 'value']) [index] per trovare l'obiettivo dell'elemento mentre si trovano più corrispondenze in esso


1
Puoi spiegare un po 'di più?
abhiarora

0

Ecco la soluzione per la variabile indice

Supponiamo che tu abbia trovato 5 elementi con lo stesso localizzatore e desideri eseguire un'azione su ogni elemento fornendo il numero di indice (qui, la variabile è usata per l'indice come "i")

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

Ci vuole XPath:

(//div[@class='className'])[1]
(//div[@class='className'])[2]
(//div[@class='className'])[3]
(//div[@class='className'])[4]
(//div[@class='className'])[5]
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.