【问题标题】:Selenium Find By Xpath returning the wrong elementSelenium Find By Xpath 返回错误的元素
【发布时间】:2015-10-04 11:11:49
【问题描述】:

我正在尝试从 HTML 表格中显示的一系列频道中选择一个频道。我正在使用以下 Selenium 方法来选择链接

WebElement channel = driver.findElement(By.xpath("//span[contains(text(),Sales)]")); channel.click();

但是,它选择了列表中的第一个频道(帐户管理)。我希望它要么选择正确的通道,要么抛出错误,而不是选择错误的通道。以下是我想要的频道的完整xpath:

/html/body/div[2]/div[2]/form/div/table/tbody[2]/tr/td/ul/li[2]/a/span

频道列表在 HTML 代码中是这样定义的:

<form action="nextpage.do" method="post" name="selectChannelForm">
<div class="de">
    <h2>Select channel</h2>
    <table id="selectChannelForm">
        <tbody id=""></tbody>
        <tbody id="">
            <tr rowtype="container">
            <td class="desecond" colspan="3">
                <ul>    
                <li>
                    <a id="selected_a" href="nextpage.do?selectedChannel=123">
                    <span>Account Management</span></a>
                </li>   
                <li>
                    <a id="selected_a" href="nextpage.do?selectedChannel=456">
                    <span>Sales</span></a>
                </li>
                <li>
                    <a id="selected_a" href="nextpage.do?selectedChannel=789">
                    <span>Complaints</span></a>
                </li>
                </ul>
            </td>
            </tr>
        </tbody>
    </table>
    <input type="hidden" value="selectChannelForm" name="formid">
</div>

【问题讨论】:

    标签: java html selenium xpath xquery


    【解决方案1】:

    首先 - 你的错误!

    您忘记了“销售”周围的引号,只需稍微更改您的代码即可:

    WebElement channel = driver.findElement(By.xpath("//span[contains(text(),'Sales')]"));
    channel.click();
    

    第二个 - xpath 错误?

    你说得对,这很奇怪,你没有收到错误消息,而是第一个元素是一个跨度。 这可能是 xpath 中的错误。 contains 函数意识到您的第二个参数不是字符串,但它不是返回 false,而是返回 true

    它实际上命中了所有三个跨度项目。因为您使用了findElement 函数,所以您只能得到第一个结果。

    试试这个,你会发现这个怪癖:

    System.out.println(driver.findElements(By.xpath("//span[contains(text(),Sales)]")).size());
    

    结果将是:

    3

    第三 - 可能是“按设计”

    查看w3c definition,您会发现以下行:

    如果 $arg2 的值是零长度字符串,那么函数 返回真。

    然后在xpath-site of microsoft你会发现另一个有趣的谜题提示:

    如果参数不是字符串类型,则首先将其转换为 字符串,然后进行评估。

    我猜,将所有这些信息放在一起,xpath 会将您的非字符串/非变量第二个参数解释为空字符串,因此自您搜索 //span 以来,所有 span 元素都返回 true。

    更新

    从我们了解到的 cmets 中的@MichaelKay,我的“猜测”非常接近:

    在 XPath 和 XQuery 中,像“hello”这样的简单名称表示 child::hello,并且 如果你没有使用模式感知,那么系统只会看起来 对于叫 hello 的孩子,如果没有,它会返回一个 空节点集。

    结论:OP 看到的行为符合设计,尽管它看起来很不直观。

    【讨论】:

    • 是的,如果 contains() 的第二个参数是一个空节点集,则答案将始终为真。
    • @MichaelKay,是的,仍然会很有趣,为什么这里这个“非字符串”被解释为一个空节点集,而不仅仅是表示错误并因此返回错误。或者更好地返回一个异常,当您在 xquery 中缺少一个字符时通常会发生什么。
    • 在 XPath 和 XQuery 中,像“hello”这样的裸名表示 child::hello,如果您没有使用模式感知,那么系统将只查找名为 hello 的子级,并且如果没有,它将返回一个空节点集。你问的是这个吗?
    • @MichaelKay 谢谢!是的,我会通过您的评论来加强我的回答,您是否还有指向此信息来源的链接以确保完整性?
    【解决方案2】:

    您使用的 xpath 在 Sales 文本周围缺少引号 ""text() 函数接受一个字符串参数,并且可以使用引号形成字符串。通过以下方式更新您的 xpath -

    driver.findElement(By.xpath("//span[contains(text(),'Sales')]")).click();
    

    或者,如果您想将其分配给 WebElement,请加上引号 -

    WebElement channel = driver.findElement(By.xpath("//span[contains(text(),'Sales')]"));
    channel.click();
    

    如果您想编写嵌套双引号或嵌套单引号,请使用转义字符\ 来编写它。方法如下 -

    WebElement channel = driver.findElement(By.xpath("//span[contains(text(),\"Sales\")]"));
    channel.click();
    

    希望这会有所帮助。

    【讨论】:

    • 哇,我现在觉得自己好傻!我觉得看了这么久让我错过了显而易见的事情。非常感谢。
    【解决方案3】:

    xpath需要修改为“//span[contains(text(),'Sales')]”。

    正如我们在下面的方法定义中看到的,只有当第二个参数也是文本时, contains 方法才会返回 true。

    来源:https://en.wikipedia.org/wiki/XPath

    包含(s1, s2) 如果 s1 包含 s2,则返回 true。 文本() 找到一个文本类型的节点

    【讨论】:

      猜你喜欢
      • 2020-12-15
      • 2019-04-21
      • 2012-03-06
      • 1970-01-01
      • 2022-01-14
      • 2018-03-25
      • 1970-01-01
      • 2021-06-23
      • 1970-01-01
      相关资源
      最近更新 更多