【问题标题】:XPath - way to select an element based on partial stringXPath - 基于部分字符串选择元素的方法
【发布时间】:2012-03-24 16:48:00
【问题描述】:

如果我在网格中列出的页面上有多个超链接,并且我只想将焦点放在第一个超链接上,有没有办法根据部分 href 文本获取对 a 标签的 href 的引用?

例如,假设页面有一堆带有汽车名称的超链接:

<a href="/Customers/7">Adam Backwell</a>
<a href="/Customers/12">Eric Mebratu</a>
<a href="/Customers/5">Dave Johnson</a>
<a href="/Customers/54">Tom Rogan</a>

所以我想为我的 xPath 做这样的事情:

"//table[@id='{0}']/a[href{1}]", usersGridId, "/Customers/");

因此,在其href 中获取第一个带有/Customers/ 的超链接。我不知道您是否可以只进行部分字符串匹配..或者换句话说,使用 XPath 进行正则表达式可以吗?在这种情况下,我不想依赖 CustomerId,因为我不知道该 Id 将是什么,因为网格是动态的。我只关心它获取对网格列表中第一个超链接的引用,不管它是谁。

更新:

忘了补充说我正在使用 XPath 和 Selenium Web 框架。

更新:

duh,我刚刚意识到我已经有那个表的参考(虽然你在这里看不到那个代码..抱歉)

所以我正在做类似 grid.FindElement(By.XPath(xPath));其中 grid 已经引用了一个表格元素。在这个表中是一个 tbody,所以我现在尝试使用这样的 a 元素:

IElement gridTable = GetCustomerGrid(); // now represents the table element that holds the customer list
xPath = string.Format("/tbody[@id='{0}']/a[1](contains(@href,'{1}')]", usersGridContainerId, "/Customers");
IWebElement hyperlink = gridTable.FindElement(By.XPath(xPath));

这个也没有运气。

还根据上面更新的代码尝试了以下方法:

string.Format("/tbody[@id='{0}']/a(contains(@href,'{1}')]",usersGridContainerId, "/Customers"); // did not find the hyperlink
string.Format("/tbody[@id='{0}']/a[1](starts-with(@href,'{1}')]",usersGridContainerId, "/Customers"); //invalid XPath Syntax error
string.Format("//tbody[@id='{0}']/a(contains(@href,'{1}')]",usersGridContainerId, "/Customers");
string.Format("//tbody[@id='{0}']/a(starts-with(@href,'{1}')]",usersGridContainerId, "/Customers");

这是我试图访问超链接的页面结构

<div class="table">
    <table id="customerList">
        <thead>
            <tr>
                <th class="column1">ID</th>
                <th class="column2">Name</th>
                <th class="column3">Email</th>
            </tr>
        </thead>
        <tbody id="custListContainer">
            <tr>
                <td class="column1">7</td>
                <td class="column2"><a href="/Customers/7">Joe Smith</a></td>
                <td>someDude@gmail.com</td>
            </tr>
        .. next user, and so on
        </tbody>
    </table>
</div>

更新:

试过了,没有运气:

string xPath = (string.Format("//tbody[@id={0}]/tr/td/a(starts-with(@href, {1})", usersTableId, " /Customers/"));
OurSeleniumDriverInstance.FindElement(By.XPath(xPath ));

【问题讨论】:

  • 此时要拔掉我的头发......真的很沮丧。

标签: c# xpath selenium


【解决方案1】:

虽然您可以使用 yajoe 所示的 XPath 来做到这一点,但如果可以的话,我还建议您使用 LINQ to XML:

var query = doc.Descendants("table")
               .Where(table => (string) table.Attribute("id") == usersGridId)
               .Elements("a")
               .Where(a => a.Attribute("href").Value.StartsWith("/Customers/"));

我更喜欢这样,因为它使“数据”部分与“代码”部分分开,很像参数化 SQL 语句。

(当然,它确实依赖于您使用 .NET 3.5 或更高版本。)

【讨论】:

  • 这很有意义,因为您可以在 xml 上使用 LINQ ...谢谢。更优雅。
  • @CoffeeAddict:只有当你有一个 XDocument 或 XElement,而不是一个 IWebElement 时,它才会起作用......如果你能把它作为真正的 XML,它应该很容易......但是如果在 Selenium 中执行此操作的首选方法是使用 XPath,这会使事情变得更加困难。
  • @CoffeeAddict:在 XPath 中,所有“特殊”部分(运算符、斜杠等)连同值一起嵌入到字符串中。与 LINQ to XML 版本相比,其中值只是表达式,有单独的方法、运算符等。例如,假设 usersGridId 可以包含单引号 - 您必须在 XPath 版本中对其进行转义,但是不在 LINQ to XML 版本中。
  • @CoffeeAddict:不仅如此——它都可以是动态的,但你仍然需要将值和代码分开。同样,我可以想象一个 XPath 版本,它允许您引用可以在外部显式设置其值的“变量”。我仍然更喜欢 LINQ to XML 方式,因为它提供了更多的编译时支持(无需先使用单独的工具来验证 XPath),但这是一个根本的区别。
  • 仅供参考,我使用完全不同的路线进行了更新。我认为我一开始就有错误的元素...请参阅原始帖子中的更新。
【解决方案2】:

是的,xpath 和 xquery 支持匹配子字符串。问题是您需要使用其中一个功能来做到这一点。您的 xpath 如下所示(好吧,您的 C# 来生成 xpath...):

"//table[@id='{0}']/a[starts-with(@href,'{1}')]", usersGridId, "/Customers/");

所有函数都在这里定义: http://www.w3schools.com/xpath/xpath_functions.asp

编辑:添加了“@”来表示 href 是一个属性。谢谢你的收获。

编辑#2:我不知道为什么我的答案未被接受——xpath 是正确的并且有效。让我印象深刻的是 a 标签不太可能是 table 标签的子标签。您是否缺少中间的 trtd 标签?

【讨论】:

  • 它不起作用....确保该元素在页面上并且我的语法与您的匹配,即 string xPath = string.Format("//table[@id='{0 }']/a[starts-with(@href,'{1}')]", usersGridId, "/Customers/");
【解决方案3】:

您可以使用 XPath starts-with 函数:

string.Format("//table[@id='{0}']/a[starts-with(@href,'/Customers/']",
       usersGridId);

注意您的 XPath 结构不正确,href 是一个属性,因此需要以 @ 符号作为前缀以表明它在属性轴上。

【讨论】:

  • 谢谢,我确实在发帖后添加了@...抓住了它。
  • 是的,它不起作用....string xPath = string.Format("//table[@id='{0}']/a[starts-with(@href,'{1 }')]", usersGridId, "/Customers/");
猜你喜欢
  • 1970-01-01
  • 2013-02-04
  • 2023-03-06
  • 1970-01-01
  • 2018-08-05
  • 2011-03-13
  • 2020-03-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多