如何使用Selenium通过索引在Xpath节点集中选择指定的节点?


91

我正在写一个硒测试用例。这是我用来匹配数据表中所有“修改”按钮的xpath表达式。

//img[@title='Modify']

我的问题是,如何按索引访问匹配的节点集?我尝试过

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

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

但是两者都没有。.我也尝试了XPath checker(一个firefox扩展名)。总共找到13个匹配项,那么我完全不知道该如何选择其中之一。 或者XPath是否支持指定选择的不在同一父节点下的节点?

Answers:


190

这是一个常见问题解答

//someName[3]

意思是someName文档中的所有元素,它们是someName其父元素的第三 个子元素-可能有很多这样的元素。

您想要的正是第三个someName元素

(//someName)[3]

说明:的[]优先级(优先级)高于//。请记住,在//someName需要指定其所选节点列表的第N个节点时,始终将类型的表达式放在方括号中。


1
非常感谢!抱歉,我完全忘记了优先事项。
Kymair Wu 2010年

1
@ Kymair-Wu:很高兴这个答案对您有用。在SO,表达感激之情的方法是接受答案(提示:单击答案旁边的复选标记)。:)
Dimitre Novatchev 2010年

@DimitreNovatchev您一遍又一遍地对相同的问题有所疑问,谢谢常见问题解答。
Eytoss 2012年

2
@Eytoss,不客气。是的,我得到的大多数+1都是相对简单的答案-并不是我认为这是我最大的成就-可能是因为每个人都理解前者,而几乎没有人理解后者:)
Dimitre Novatchev 2012年

2
@TEHEMPRAH,实际上我在回答中看到我没有说“其父级的第三个'someName'子级”。感谢您注意到这一点。现在已更正。
Dimitre Novatchev

14

iXPath中没有。

您可以使用文字数字: //img[@title='Modify'][1]

或者,您可以动态构建表达式字符串:('//img[@title='Modify']['+i+']'但请注意,动态XPath表达式不能 XSLT 内部运行)。

还是XPath支持指定选择不在同一父节点下的节点?

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


//img[@title='Modify'][i]意味着“ <img>标题为'Modify'并且子元素名为的任何人<i>。”


由于某种原因,我需要在属性表达式之前包括索引。例如,要查找td是a的第六个子tr//tr/td[6][string-length(text()) > 0]
元素

1
@kopranb有关说明,请参见此答案stackoverflow.com/a/1006439/18771
Tomalak

感谢您解释'// 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'])[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]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.