当属性包含多个单词时,按属性选择节点时遇到问题。例如:
<div class="atag btag" />
这是我的xpath表达式:
//*[@class='atag']
该表达式适用于
<div class="atag" />
但不适用于前面的示例。如何选择<div>?
div.atag或的原因div.btag。超级简单,不匹配字符串,并且WAY更快(并且在浏览器中更好地支持)。XPath(针对HTML)应该归结为有用的……通过包含的文本查找元素以及进行DOM导航。
当属性包含多个单词时,按属性选择节点时遇到问题。例如:
<div class="atag btag" />
这是我的xpath表达式:
//*[@class='atag']
该表达式适用于
<div class="atag" />
但不适用于前面的示例。如何选择<div>?
div.atag或的原因div.btag。超级简单,不匹配字符串,并且WAY更快(并且在浏览器中更好地支持)。XPath(针对HTML)应该归结为有用的……通过包含的文本查找元素以及进行DOM导航。
Answers:
这是一个示例,该示例查找其className包含的div元素atag:
//div[contains(@class, 'atag')]
这是一个示例,该示例查找其className包含atag和的div元素btag:
//div[contains(@class, 'atag') and contains(@class ,'btag')]
但是,它还会找到部分匹配项,例如class="catag bobtag"。
如果您不希望部分匹配,请参阅下面的bobince答案。
<div class="Patagonia Halbtagsarbeit">,其中包含目标字符串,但不是具有给定类的div。
mjv的答案是一个好的开始,但是如果atag不是列出的第一个类名,它将失败。
通常的方法比较笨拙:
//*[contains(concat(' ', @class, ' '), ' atag ')]
只要类仅由空格(而不是其他形式的空格)分隔,此方法就起作用。几乎总是这样。如果不是这样,则必须使它更加笨拙:
//*[contains(concat(' ', normalize-space(@class), ' '), ' atag ')]
(通过类名分隔的字符串进行选择是一种常见的情况,令人惊讶的是,没有像CSS3的'[class〜=“ atag”]'这样的特定XPath函数。)
编辑:请参阅bobince的解决方案,该解决方案使用contains而不是start-with,以及确保在完整令牌级别进行比较的技巧(请注意,将“ atag”模式作为另一个“ tag”的一部分找到)。
“ atag btag”是class属性的一个奇数值,但更是如此,请尝试:
//*[starts-with(@class,"atag")]
一个有效的2.0 XPath:
//*[tokenize(@class,'\s+')='atag']
或带有变量:
//*[tokenize(@class,'\s+')=$classname]
@class有多个元素,怎么办?因为它将返回单词列表,并将其与字符串进行比较失败,并且基数错误。
//*[tokenize(@class)=$classname]
//*[@class=$classname]
请注意,如果您可以假设感兴趣的类名不是另一个可能的类名的子字符串,bobince的答案可能会过于复杂。如果是这样,则可以通过contains函数简单地使用子字符串匹配。以下内容将匹配其类包含子字符串'atag'的任何元素:
//*[contains(@class,'atag')]
如果上述假设不成立,则子字符串匹配将匹配您不想要的元素。在这种情况下,您必须找到边界字。通过使用空格定界符来查找类名称边界,bobince的第二个答案将找到确切的匹配项:
//*[contains(concat(' ', normalize-space(@class), ' '), ' atag ')]
这将匹配atag而不匹配matag。
添加到bobince的答案...如果您使用的任何工具/库都使用Xpath 2.0,您也可以执行以下操作:
//*[count(index-of(tokenize(@class, '\s+' ), $classname)) = 1]
显然需要count(),因为index-of()返回字符串中与之匹配的每个索引的序列。
$classname变量放在引号之间?因为它就是一个字符串。
'$classname',还有一个正确的(兼容JavasScript的)getElementsByClassName ...实现。