如何匹配包含某个字符串的属性?
Posted
技术标签:
【中文标题】如何匹配包含某个字符串的属性?【英文标题】:How can I match on an attribute that contains a certain string? 【发布时间】:2010-11-26 07:25:05 【问题描述】:当属性包含多个单词时,我在按属性选择节点时遇到问题。例如:
<div class="atag btag" />
这是我的 xpath 表达式:
//*[@class='atag']
表达式适用于
<div class="atag" />
但不是前面的例子。如何选择<div>
?
【问题讨论】:
我认为值得指出的是,“atag btag”是一个属性,而不是两个。您正在尝试在 xpath 中进行子字符串匹配。 是的,你是对的——这就是我想要的。 相关:***.com/questions/8808921/… 和 ***.com/questions/1604471/… 这就是为什么你应该使用 CSS 选择器...div.atag
或div.btag
。超级简单,不是字符串匹配,而且速度更快(并且在浏览器中得到更好的支持)。 XPath(针对 html)应该归结为它对...通过包含的文本查找元素和 DOM 导航有用。
【参考方案1】:
EDIT:查看 bobince 的解决方案,它使用 contains 而不是 start-with,以及确保比较在完整令牌的级别(以免将“atag”模式作为另一个“标签”的一部分找到)。
"atag btag" 是类属性的奇数,但永远不会少,试试吧:
//*[starts-with(@class,"atag")]
【讨论】:
如果你的 XPath 引擎支持starts-with 命令,你可以使用它,例如我记得JVM 6 不支持它 @mjv:CSS 类属性指定多个值是很常见的。 CSS就是这样完成的。 @mjv 您不能保证该名称会出现在类属性的开头。 @thuktun @skaffman。谢谢,伟大的cmets。我相应地“重定向”到 bobince 解决方案。 不适用于与上述等效的 【参考方案2】: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 正式发布之前编写的。见***.com/a/12165032/423105 或***.com/a/12165195/423105 不要像我一样,在这个例子中删除你正在寻找的类周围的空格;它们实际上很重要。否则,它可能看起来有效,但却达不到目的。【参考方案3】:这是一个查找 className 包含 atag
的 div 元素的示例:
//div[contains(@class, 'atag')]
下面是一个示例,它查找 className 包含 atag
和 btag
的 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.
对不起,这不匹配一个类,它匹配一个子字符串
这显然是错误的,因为它还发现: 它不应该这样做。
问题是“包含某个字符串”而不是“匹配某个类”【参考方案4】:
要添加到 bobince 的答案... 如果您使用的任何工具/库使用 Xpath 2.0,您也可以这样做:
//*[count(index-of(tokenize(@class, '\s+' ), $classname)) = 1]
count() 显然是需要的,因为 index-of() 返回它在字符串中匹配的每个索引的序列。
【讨论】:
我想你的意思是不要把$classname
变量放在引号之间?因为它是一个字符串。
最后,一个正确的(JavasScript 兼容的)getElementsByClassName 实现......当然除了字符串文字'$classname'
。
这太复杂了。有关正确的 XPath 2.0 答案,请参阅 @DanielHaley 的回复。【参考方案5】:
有效的 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]
【参考方案6】:
试试这个://*[contains(@class, 'atag')]
【讨论】:
如果类名是grabatagonabag
怎么办? (提示:它仍然会匹配。)【参考方案7】:
你可以试试下面的
By.CssSelector("div.atag.btag")
【讨论】:
【参考方案8】:请注意,如果您可以假设 您感兴趣的类名不是另一个可能的类名的子字符串,那么 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,所以这是唯一可行的解决方案。【参考方案9】:对于包含公共 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();
【讨论】:
【参考方案10】:我来这里是为了寻找 Ranorex Studio 9.0.1 的解决方案。那里还没有 contains() 。相反,我们可以使用正则表达式:
div[@class~'atag']
【讨论】:
以上是关于如何匹配包含某个字符串的属性?的主要内容,如果未能解决你的问题,请参考以下文章