但不是前面的例子。如何选择
?" /> 但不是前面的例子。如何选择
?"> 但不是前面的例子。如何选择
?" />
ChatGPT解决这个技术问题 Extra ChatGPT

如何匹配包含某个字符串的属性?

当属性包含多个单词时,我在按属性选择节点时遇到问题。例如:

<div class="atag btag" />

这是我的 xpath 表达式:

//*[@class='atag']

该表达式适用于

<div class="atag" />

但不是前面的例子。如何选择 <div>

我认为值得指出的是,“atag btag”是一个属性,而不是两个。您正在尝试在 xpath 中进行子字符串匹配。
是的,你是对的——这就是我想要的。
这就是为什么您应该使用 CSS 选择器... div.atagdiv.btag。超级简单,不是字符串匹配,而且速度更快(并且在浏览器中得到更好的支持)。 XPath(针对 HTML)应该归结为它对...通过包含的文本查找元素和 DOM 导航有用。

P
Pikamander2

下面是一个查找 className 包含 atag 的 div 元素的示例:

//div[contains(@class, 'atag')]

下面是一个查找 className 包含 atagbtag 的 div 元素的示例:

//div[contains(@class, 'atag') and contains(@class ,'btag')]

但是,它也会找到部分匹配项,例如 class="catag bobtag"

如果您不想要部分匹配,请参阅下面的 bobince 答案。


@Redbeard:这是一个字面的答案,但通常不是类匹配解决方案的目标。特别是它会匹配 <div class="Patagonia Halbtagsarbeit">,它包含目标字符串但不是具有给定类的 div。
这将适用于简单的场景 - 但请注意您是否想在更广泛的上下文中使用此答案,而对您正在检查的属性值的控制较少或没有控制。 The correct answer is bobince's.
抱歉,这不匹配一个类,它匹配一个子字符串
它也发现它显然是错误的:
它不应该这样做。
问题是“包含某个字符串”而不是“匹配某个类”
J
Jens Erat

mjv 的回答是一个好的开始,但如果 atag 不是列出的第一个类名,则会失败。

通常的方法是相当笨拙的:

//*[contains(concat(' ', @class, ' '), ' atag ')]

只要类仅由空格分隔,而不是其他形式的空格,则此方法有效。几乎总是这样。如果它可能不是,你必须让它更笨重:

//*[contains(concat(' ', normalize-space(@class), ' '), ' atag ')]

(通过类似类名的空格分隔字符串进行选择是一种常见的情况,令人惊讶的是它没有特定的 XPath 函数,如 CSS3 的 '[class~="atag"]'。)


呸,xpath 需要一些修复
@Redbeard supra123 的答案是有问题的,如果您不想选择像“atagnumbertwo”这样的 css 类,但我承认这可能不太可能(:
@crazyrails:您能接受这个答案作为正确答案吗?这将有助于未来的搜索者确定您问题所描述问题的正确解决方案。谢谢!
@cha0site:是的,他们可以,在 XPath 2.0 及以下版本中。这个答案是在 XPath 2.0 正式发布之前编写的。请参阅 stackoverflow.com/a/12165032/423105stackoverflow.com/a/12165195/423105
不要像我一样,在这个例子中删除你正在寻找的类周围的空格;它们实际上很重要。否则,它可能看起来有效,但却达不到目的。
S
SelenUser

试试这个://*[contains(@class, 'atag')]


如果类名是 grabatagonabag 怎么办? (提示:它仍然会匹配。)
J
Jens Erat

编辑:请参阅 bobince 的解决方案,该解决方案使用包含而不是开头,以及确保在完整令牌级别完成比较的技巧(以免发现“atag”模式作为另一个“标签”的一部分)。

“atag btag” 是类属性的奇数,但无论如何,请尝试:

//*[starts-with(@class,"atag")]

如果您的 XPath 引擎支持starts-with 命令,您可以使用它,例如,据我记忆,JVM 6 不支持它
@mjv:CSS 类属性指定多个值很常见。这就是 CSS 的完成方式。
@mjv您不能保证该名称将出现在类属性的开头。
@thuktun @skaffman。谢谢,很棒的评论。我相应地“重定向”到 bobince 解决方案。
不适用于与上述等效的
J
Jens Erat

一个有效的 2.0 XPath:

//*[tokenize(@class,'\s+')='atag']

或使用变量:

//*[tokenize(@class,'\s+')=$classname]

如果 @class 有多个元素,这将如何工作?因为它将返回一个单词列表并将其与字符串进行比较失败,错误的基数
@AlexisWilke - 来自规范 (w3.org/TR/xpath20/#id-general-comparisons):一般比较是存在量化的比较,可以应用于任何长度的操作数序列。它适用于我尝试过的每个 2.0 处理器。
另请注意,在 XPath 3.1 中,这可以简化为 //*[tokenize(@class)=$classname]
为了完整起见,如果您有幸使用了模式感知 XPath 处理器,并且如果 @class 具有列表值类型,那么您可以简单地编写 //*[@class=$classname]
B
Brent Atkinson

请注意,如果您可以假设您感兴趣的类名不是另一个可能的类名的子字符串,那么 bobince 的答案可能过于复杂。如果这是真的,您可以通过 contains 函数简单地使用子字符串匹配。以下将匹配其类包含子字符串“atag”的任何元素:

//*[contains(@class,'atag')]

如果上述假设不成立,则子字符串匹配将匹配您不想要的元素。在这种情况下,您必须找到单词边界。通过使用空格分隔符来查找类名边界,bobince 的第二个答案找到了完全匹配:

//*[contains(concat(' ', normalize-space(@class), ' '), ' atag ')]

这将匹配 atag 而不是 matag


这是我一直在寻找的解决方案。它清楚地在 class='hello test world' 中找到 'test' 并且与 'hello test-test world' 不匹配。因为我只使用 XPath 1.0 并且没有 RegEx,所以这是唯一可行的解决方案。
这与@bobince 的回答有何不同?
@Nakilon 最完整的解决方案是我在这里提出的第二个,与 bobince 的第二个答案相同。然而,第一个解决方案更容易理解和阅读,但只有当你的类名不能是彼此的子字符串时才会正确。第二个更通用,但如果假设对您的特定应用程序是合理的,则第一个更可取。
D
Demi

要添加到 bobince 的答案...如果您使用的任何工具/库使用 Xpath 2.0,您也可以这样做:

//*[count(index-of(tokenize(@class, '\s+' ), $classname)) = 1]

count() 显然是需要的,因为 index-of() 返回它在字符串中匹配的每个索引的序列。


我想您的意思是不要将 $classname 变量放在引号之间?因为它是一个字符串。
最后,getElementsByClassName 的正确(JavasScript 兼容)实现......当然,除了字符串文字 '$classname'
这是非常复杂的。有关正确的 XPath 2.0 答案,请参阅@DanielHaley 的回复。
G
Guilherme Franco

您可以尝试以下方法

By.CssSelector("div.atag.btag")


J
Jarno Argillander

我来这里寻找 Ranorex Studio 9.0.1 的解决方案。那里还没有 contains() 。相反,我们可以使用正则表达式,例如:

div[@class~'atag']

N
Nathaniel Ford

对于包含公共 url 的链接,必须在变量中进行控制台。然后依次尝试。

webelements allLinks=driver.findelements(By.xpath("//a[contains(@href,'http://122.11.38.214/dl/appdl/application/apk')]"));
int linkCount=allLinks.length();
for(int i=0; <linkCount;i++)
{
    driver.findelement(allLinks[i]).click();
}