Wie wähle ich mit Selen einen bestimmten Knoten in Xpath-Knotensätzen nach Index aus?

91

Ich schreibe einen Selen-Testfall. Und hier ist der xpath-Ausdruck, den ich verwende, um alle 'Modify'-Schaltflächen in einer Datentabelle abzugleichen.

//img[@title='Modify']

Meine Frage ist, wie kann ich die übereinstimmenden Knotensätze nach Index besuchen? Ich habe es mit versucht

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

und

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

Aber beides funktioniert nicht. Ich habe es auch mit XPath Checker (One Firefox-Erweiterung) versucht. Es wurden insgesamt 13 Übereinstimmungen gefunden, dann habe ich keine Ahnung, wie ich eine davon auswählen soll. Oder unterstützt XPath die angegebene Auswahl von Knoten, die sich nicht unter demselben übergeordneten Knoten befinden?

Kymair Wu
quelle

Antworten:

189

Dies ist eine FAQ :

//someName[3]

bedeutet : alle someNameElemente im Dokument, die das dritte someNameKind ihres Elternteils sind - es kann viele solcher Elemente geben.

Was Sie wollen, ist genau das 3. someNameElement :

(//someName)[3]

Erläuterung : Das []hat eine höhere Priorität (Priorität) als //. Denken Sie daran, Ausdrücke des Typs immer //someNamein Klammern zu setzen, wenn Sie den N-ten Knoten der ausgewählten Knotenliste angeben müssen.

Dimitre Novatchev
quelle
1
Vielen Dank! Tut mir leid, ich habe die Vorrang-Dinge total vergessen. Ich habe es gerade versucht und es funktioniert!
Kymair Wu
1
@ Kymair-Wu: Ich bin froh, dass diese Antwort für Sie nützlich war. Hier bei SO können Sie Dankbarkeit ausdrücken, indem Sie eine Antwort annehmen (Hinweis: Klicken Sie auf das Häkchen neben der Antwort). :)
Dimitre Novatchev
@DimitreNovatchev Sie erhalten immer wieder Punkte für dieselbe Frage: p, danke für die FAQ.
Eytoss
2
@ Eytoss, Gern geschehen. Und ja, ich bekomme die meisten +1 für relativ einfache Antworten - nicht für die Antworten, von denen ich glaube, dass sie meine größten Erfolge sind - wahrscheinlich, weil jeder die ersteren versteht und fast niemand die letzteren versteht :)
Dimitre Novatchev
2
@TEHEMPRAH, Eigentlich habe ich gesehen, dass ich in der Antwort nicht "das 3. 'someName'-Kind seines Elternteils" gesagt habe. Danke, dass du das bemerkt hast. Jetzt korrigiert.
Dimitre Novatchev
14

Es gibt keine iin XPath.

Entweder verwenden Sie Literalzahlen: //img[@title='Modify'][1]

Oder Sie erstellen die Ausdruckszeichenfolge dynamisch: '//img[@title='Modify']['+i+']'( Beachten Sie jedoch, dass dynamische XPath-Ausdrücke in XSLT nicht funktionieren .)

Oder unterstützt XPath die angegebene Auswahl von Knoten, die sich nicht unter demselben übergeordneten Knoten befinden?

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


Dies //img[@title='Modify'][i]bedeutet "alle <img>mit dem Titel" Ändern "und einem untergeordneten Element mit dem Namen <i>".

Tomalak
quelle
Aus irgendeinem Grund musste ich den Index vor dem Attributausdruck einfügen. Zum Beispiel, um tds zu finden , die das sechste Kind von a waren trund keinen leeren Inhalt haben://tr/td[6][string-length(text()) > 0]
Samir Aguiar
1
@kopranb Eine Erklärung finden Sie in dieser Antwort stackoverflow.com/a/1006439/18771
Tomalak
Vielen Dank für die Erklärung zu '// img [@ title =' Modify '] [' + i + ']' (+1)
DebanjanB
2
//img[@title='Modify'][i]

Kurzform für

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

Daher wird der i-te Knoten unter demselben übergeordneten Knoten zurückgegeben.

Sie wollen

/descendant-or-self::img[@title='Modify'][i]
Nick Jones
quelle
1
/descendant::img[@title='Modify'][$index]Wird einfach gut funktionieren. Beachten Sie auch den [i]Prädikattest für die Existenz eines iuntergeordneten Elements.
2

Es gibt kein iin xpath ist nicht ganz wahr. Sie können weiterhin count()den Index verwenden , um ihn zu finden.

Betrachten Sie die folgende Seite

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

Die Seite hat 2 Tabellen und 6 Spalten mit jeweils eindeutigen Spaltennamen und 6 Zeilen mit variablen Daten. Die letzte Zeile enthält die ModifySchaltfläche in beiden Tabellen.

Angenommen, der Benutzer muss die 4. ModifySchaltfläche aus der ersten Tabelle basierend auf der Überschrift auswählen

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

In count()solchen Situationen ist der Bediener praktisch.

Logik:

  1. Suchen Sie die Überschrift für die ModifySchaltfläche mit//th[.='Heading 4']
  2. Finden Sie den Index der Kopfspalte mit count(//tr/th[.='Heading 4']/preceding-sibling::th)+1

Hinweis: Der Index beginnt bei0

  1. Holen Sie sich die Zeilen für den entsprechenden Header mit //th[.='Heading 4']/ancestor::thead/following-sibling::tbody/tr/td[count(//tr/th[.='Heading 4']/preceding-sibling::th)+1]

  2. Holen Sie sich die ModifySchaltfläche aus der extrahierten Knotenliste mit//th[.='Heading 4']/ancestor::thead/following-sibling::tbody/tr/td[count(//tr/th[.='Heading 4']/preceding-sibling::th)+1]/button

Eric Stanley
quelle
1

(// * [@ attribute = 'value']) [index], um das Ziel des Elements zu finden, während Sie mehrere Übereinstimmungen darin finden

Mahesh
quelle
1
Können Sie uns etwas mehr erklären?
Abhiarora
0

Hier ist die Lösung für die Indexvariable

Angenommen, Sie haben 5 Elemente mit demselben Locator gefunden und möchten für jedes Element eine Aktion ausführen, indem Sie die Indexnummer angeben (hier wird die Variable für den Index als "i" verwendet).

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

Es braucht XPath:

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