如何匹配包含特定字符串的属性?

cra*_*ils 432 xpath

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

<div class="atag btag" />
Run Code Online (Sandbox Code Playgroud)

这是我的xpath表达式:

//*[@class='atag']

表达式适用于

<div class="atag" />

但不是前一个例子.我该如何选择<div>

小智 473

无论属性的位置如何,都将选择它们

//div[contains(@class, 'atag') and contains(@class ,'btag')]
Run Code Online (Sandbox Code Playgroud)

  • @Redbeard:这是一个字面上的答案,但通常不是一个类匹配解决方案的目标.特别是它匹配`<div class ="Patagonia Halbtagsarbeit">`,它包含目标字符串,但不是具有给定类的div. (122认同)
  • 对不起,这与一个类不匹配,它匹配一个子字符串 (16认同)
  • 问题是"包含某个字符串"而不是"匹配某个类" (6认同)
  • 这显然是错误的,因为它也发现:<div class ="annatag bobtag">它不应该. (5认同)
  • 这适用于简单的场景 - 但要注意是否要在更广泛的上下文中使用此答案,而对要检查的属性值的控制较少或无法控制.[正确答案是bobince的.](http://stackoverflow.com/a/1390680/177710) (3认同)

bob*_*nce 298

mjv的答案是一个良好的开端,但如果atag不是列出的第一个类名,则会失败.

通常的方法是相当笨拙:

//*[contains(concat(' ', @class, ' '), ' atag ')]
Run Code Online (Sandbox Code Playgroud)

只要类仅由空格分隔,而不是其他形式的空格,这就可以工作.几乎总是如此.如果它可能不是,你必须使它更加笨拙:

//*[contains(concat(' ', normalize-space(@class), ' '), ' atag ')]
Run Code Online (Sandbox Code Playgroud)

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

  • 呸,xpath需要一些修复 (55认同)
  • @Redbeard supra123的答案是有问题的,如果你不想选择像"atagnumbertwo"这样的css类,虽然我承认这可能不太可能(: (13认同)
  • @crazyrails:你能否接受这个答案作为正确的答案?这将有助于未来的搜索者找到问题描述的问题的正确解决方案.谢谢! (7认同)
  • @ cha0site:是的,他们可以在XPath 2.0及以下版本中使用.这个答案是在XPath 2.0正式发布之前编写的.请参阅http://stackoverflow.com/a/12165032/423105或http://stackoverflow.com/a/12165195/423105 (2认同)

mjv*_*mjv 38

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

"atag btag"是类属性的奇数值,但从不如此,请尝试:

//*[starts-with(@class,"atag")]
Run Code Online (Sandbox Code Playgroud)

  • @mjv:CSS类属性通常指定多个值.这就是CSS的完成方式. (9认同)
  • @mjv您不能保证该名称将出现在class属性的开头. (6认同)

Sel*_*ser 34

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

  • 如果类名是“grabatagonabag”怎么办?(提示:它仍然会匹配。) (2认同)

Dan*_*ley 30

一个有效的2.0 XPath:

//*[tokenize(@class,'\s+')='atag']
Run Code Online (Sandbox Code Playgroud)

或者使用变量:

//*[tokenize(@class,'\s+')=$classname]
Run Code Online (Sandbox Code Playgroud)

  • @AlexisWilke - 来自规范(http://www.w3.org/TR/xpath20/#id-general-comparisons):*一般比较是存在量化的比较,可以应用于任何长度的操作数序列.*它的工作原理在我试过的每个2.0处理器中. (3认同)
  • 另请注意,在 XPath 3.1 中,这可以简化为 `//*[tokenize(@class)=$classname]` (2认同)
  • 为了完整起见,如果您有幸使用模式感知的 XPath 处理器,并且 @class 具有列表值类型,那么您可以简单地编写 `//*[@class=$classname]` (2认同)

小智 21

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

//*[contains(@class,'atag')]
Run Code Online (Sandbox Code Playgroud)

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

//*[contains(concat(' ', normalize-space(@class), ' '), ' atag ')]
Run Code Online (Sandbox Code Playgroud)

这将匹配atag而不是matag.


arm*_*eys 7

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

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

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


小智 5

您可以尝试以下

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