XPath:选择以下兄弟姐妹直到某个班级

Jon*_*eir 5 xpath

我有以下html代码段:

<table>
    <tr>
        <td class="foo">a</td>
            <td class="bar">1</td>
            <td class="bar">2</td>
        <td class="foo">b</td>
            <td class="bar">3</td>
            <td class="bar">4</td>
            <td class="bar">5</td>
        <td class="foo">c</td>
            <td class="bar">6</td>
            <td class="bar">7</td>
    </tr>
</table>
Run Code Online (Sandbox Code Playgroud)

我正在寻找一个XPath 1.0表达式,它从一个.foo元素开始,并.bar在下一个元素之前选择所有后续.foo元素.
例如:我开始a并且只想选择12.
或者我开始b并想要选择3,45.

背景:我必须为此方法找到一个XPath表达式(使用Java和Selenium):

public List<WebElement> bar(WebElement foo) {
    return foo.findElements(By.xpath("./following-sibling::td[@class='bar']..."));
}
Run Code Online (Sandbox Code Playgroud)

有办法解决问题吗?
表达式应该适用于所有.foo元素,而不使用任何外部变量.

谢谢你的帮助!

更新:这些特殊情况显然没有解决方案.但是如果您的限制较少,则提供的表达式可以完美地运行.

Abe*_*bel 4

好问题!

根据输入,以下表达式将为您提供1..2,3..56..7X + 1,其中X是您想要的集合(2 给出 1-2,3 给出 3-.5 等)。在示例中,我选择第三组,因此它具有[4]

/table/tr[1]
  /td[not(@class = 'foo')]
  [
     generate-id(../td[@class='foo'][4]) 
     = generate-id(
         preceding-sibling::td[@class='foo'][1]
        /following-sibling::td[@class='foo'][1])
  ]
Run Code Online (Sandbox Code Playgroud)

该表达式 (imnsho) 的优点在于,您可以按给定的集合进行索引(而不是按相对位置进行索引),并且只有一处需要更新表达式。如果您想要第六组,只需输入[7]

此表达式适用于任何有兄弟节点的情况,即您需要具有相同需求的任意两个节点之间的兄弟节点 ( @class = 'foo')。我将更新并解释。

将表达式中的替换[4]为您需要的任何设置,再加上 1。在 oXygen 中,上面的表达式显示了以下选择:

在此输入图像描述

解释

/table/tr[1]
Run Code Online (Sandbox Code Playgroud)

选择第一个tr.

/td[not(@class = 'foo')]
Run Code Online (Sandbox Code Playgroud)

选择任何tdfoo

generate-id(../td[@class='foo'][4])
Run Code Online (Sandbox Code Playgroud)

获取 xth 的标识foo,在本例中,选择空并返回空。在所有其他情况下,它将返回我们感兴趣的下一个的身份foo

generate-id(
    preceding-sibling::td[@class='foo'][1]
    /following-sibling::td[@class='foo'][1])
Run Code Online (Sandbox Code Playgroud)

获取第一个前一个的标识foo(从任何非 foo 元素开始向后计数),并从那里开始获取第一个后一个foo. 在节点 的情况下7,这会返回虚无的标识,​​从而导致true我们的示例情况为[4]。在节点的情况下3,这将导致c,它不等于无,从而导致false

如果该示例具有值,则最后一位将返回节点和 的[2]节点,这等于返回的标识。对于节点b12../td[@class='foo'][2]true47,这将返回false

更新,替代方案#1

我们可以generate-id用 count-preceding-sibling 函数替换该函数。由于两个节点之前的兄弟节点数量foo各不相同,因此这可以作为以下方法的替代方案:generate-id

不过,现在它开始变得像 GSerg 的答案一样实用:

/table/tr[1]
  /td[not(@class = 'foo')]
  [
     count(../td[@class='foo'][4]/preceding-sibling::*) 
     = count(
         preceding-sibling::td[@class='foo'][1]
        /following-sibling::td[@class='foo'][1]/preceding-sibling::*)
  ]
Run Code Online (Sandbox Code Playgroud)

应用相同的“索引”方法。我[4]上面写的地方,将其替换为您感兴趣的n + 1个交叉点位置。

  • @GSerg,Selenium 使用[浏览器的 XPath 功能](http://acdcjunior.github.io/xpath-2-3-version-selenium-webdriver-support.html)。据我所知,浏览器支持generate-id功能。虽然我承认,我还没有尝试过硒。 (2认同)
  • @JonasStaudenmeir 这意味着您需要能够[从内部谓词获取外部谓词的上下文](http://stackoverflow.com/q/6595034/11683)。有能力的人说你[不能用 XPath 1.0 表达式做到这一点](http://stackoverflow.com/a/6599393/11683)。顺便说一句,如果这是您的情况,为什么不能针对该上下文节点进行多个 xpath 查询?第一个获取下一个“foo”(如果有),另外两个获取两组“bar”,然后使用引用相等手动减去这两组? (2认同)
  • @JonasStaudenmeir,正如 GSerg 所说。除非您设法在支持“current()”和“generate-id()”的浏览器中使用 Selenium,否则这(实际上?)是不可能的。[Lingamurthy 的解决方案解决了这个问题](http://stackoverflow.com/a/32556004/111575) 使用与我演示的类似的技术,但随后将上下文节点设置为“foo” td 之一。这需要这两个功能。 (2认同)