在我的Selenium应用程序中,我尝试选择具有最高z-index
的元素。该值未在元素本身中定义,而是在祖先节点上定义(嵌套级别未知)。此外,如果使用display: none
看不到祖先,则不应返回。
示例HTML:
<div class="container" style="z-index: 10">
<div style="display: none">
<!-- this should not be selected because it is invisible (and the z-index is lower than the others) -->
<div myattr="example"></div>
</div>
</div>
<div class="container" style="z-index: 100">
<div>
<!-- this should not be selected because the z-index is lower than the others -->
<div myattr="example"></div>
</div>
</div>
<div class="container" style="z-index: 1000">
<div>
<!-- this should be selected because it is visible and has the highest z-index -->
<div myattr="example"></div>
</div>
</div>
目前我有一个正则表达式,选择myattr="example"
所有没有祖先display: none
的元素:
//div[@myattr='example'
and not(ancestor::div[contains(@style,'display:none')])
and not(ancestor::div[contains(@style,'display: none')])]
我需要一个额外的条件来选择具有最高z-index的元素,所以可以说哪个元素在其他元素之上是可见的。对于每个找到的节点,必须查看所有祖先,直到找到具有特定类的节点(在此示例中为container
)。然后只返回具有最高z-index祖先的元素。
XPath甚至可以实现吗?
答案 0 :(得分:1)
我假设你知道z-index的最高值,在这种情况下xpath是
"//div[contains(@style,'1000')]/div[not(contains(@style,'none'))]/div"
否则使用下面的xpath获取div的所有样式属性
List<WebElement> divTags=driver.findElements(By.xpath("//div[not(contains(@style,'none'))]/parent::div[contains(@style,'z-index')]"))
for(WebElement ele:divTags)
{
ele.getAttribute("style");
}
我希望上面的逻辑可以帮助你实现目标。
答案 1 :(得分:1)
我努力尝试,但我认为你无法用一个XPath 1.0表达式实现这一点。你可以近距离接触,但不是很接近。
你需要使用其他一些逻辑。有一千种不同的方法。
例如,获取所有container
元素,按z-index
对其进行排序,并测试其myattr="example"
个后代的可见性:
// Gets all containers - could also be Gets all elements containing z-index
List<WebElement> containers = driver.findElements(By.className("container"));
// Sorts the containers in an descending order by their z-indexes
Collections.sort(containers, Collections.reverseOrder(new Comparator<WebElement>() {
@Override
public int compare(WebElement o1, WebElement o2) {
return getZindex(o1) - getZindex(o2);
}
private int getZindex(WebElement elem) {
String zindex = elem.getAttribute("style").toLowerCase().replace("z-index: ", "");
return Integer.parseInt(zindex);
}
}));
// look for a visible candidate to return as a result
for (WebElement container : containers) {
WebElement result = container.findElement(By.cssSelector("*[myattr='example']"));
if (result.isDisplayed()) {
return result;
}
}
throw new IllegalStateException("No element found.");
编辑:在您接受此答案后,我回到了问题并想出了一个XPath 1.0解决方案。它太丑了,表现不佳,我无法验证它的正确性(它适用于你的例子以及我试过的其他几个),所以我建议你使用上面的WebDriver方法。无论如何,我会分享它:
Copypastable oneliner:
//div[@myattr='example' and not(ancestor::div[contains(@style,'display: none')])]/ancestor::div[@class='container' and substring-after(@style,'z-index:') > substring-after(../div[not(descendant::div[contains(@style,'display: none')])]/@style,'z-index:')]
格式化版本:
//div
[
@myattr='example'
and not(ancestor::div[contains(@style,'display: none')])
]
/ancestor::div
[
@class='container'
and substring-after(@style,'z-index:')
> substring-after(
../div[not(descendant::div[contains(@style,'display: none')])]/@style,
'z-index:')
]
免费翻译为人类语言(不是字面的!):
SELECT A VISIBLE <div @myattr='example'> NODE
//div
[
@myattr='example'
and not(ancestor::div[contains(@style,'display: none')])
]
THAT HAS A <div @class='container'> ANCESTOR
/ancestor::div
[
@class='container'
WHOSE z-index IS GREATER THAN z-index...
and substring-after(@style,'z-index:')
> substring-after(
...OF ALL VISIBLE SIBLINGS
../div[not(descendant::div[contains(@style,'display: none')])]/@style,
'z-index:')
]