我们在自动化测试中会经常使用到xpath来进行对象的选择。之前我写过的一篇关于自动化测试对象定位的八种常用方式中,也介绍了一些xpath的基本表达式。但有些比较特殊的情况中,仅靠这些比较基本的xpath表达式还不够灵活,所以今天继续介绍几种比较常用的基于“轴(Axes)”的表达式。
本文中的示例HTML代码为http://www.guru99.com,代码使用的区域为如下图所示,大家可以在该页面中对照试验代码:
$x("//a[contains(text(), ‘Learn SQL’)]/following::a[contains(text(), ‘Learn Python’)]")
该表达式中,//a[contains(text(), ‘Learn SQL’)]定位到了含有Learn SQL文字的a标签,接着following::a能够找到上面这个a标签后面的所有a标签,而哪个才是我们要找的a标签对象呢?contains(text(), ‘Learn Python’)包含了该a标签必须满足的条件,所以最终我们就顺利找到了想要找到的对象。
preceding::与following::基本类似,前者表示查找的目标在当前节点之前,后者表示查找的目标在当前节点之后,仅此而已。在实际运用时,需要根据实际情况进行选择。
$x("//a[contains(text(), ‘Learn SQL’)]/parent::li/following-sibling::li/a[contains(text(), ‘Learn Python’)]")
其中,parent::li指定前面a标签的父级li元素,然后在following-sibling::li中找到parent::li的兄弟li节点,最后通过a[contains(text(), ‘Learn Python’)]找到兄弟li节点下的包含Learn Python的a标签,目标完成。
preceding-sibling完全类似,就不再赘述。
$x("//a[contains(text(), ‘Learn SQL’)]/parent::li/following-sibling::li/child::a[contains(text(), ‘Learn Python’)]")
$x("//a[contains(text(), ‘Learn SQL’)]/ancestor::div[@class=‘featured-box’]/descendant::b[.=‘Web’]")
ancestor::div[@class=‘featured-box’]可定位到Learn SQL的父级节点中含有class属性为’featured-box’的元素,而标题Web正是该div的孙子节点之一,所以我们加上descendant::b[.=‘Web’]即可找到目标节点。
再进一步思考一下,如果我们将上面的xpath改为$x("//a[contains(text(), ‘Learn SQL’)]/ancestor::div[@class=‘featured-box’]/child::b[.=‘Web’]"),还能找到我们想要的节点吗?答案是不能,因为标题Web是div[@class=‘featured-box’]的孙子节点,而非直接的子节点,所以是不能用child的。
另外,还有几个小的tips,灵活运用也可以使得我们书写xpath更加灵活,一并记之。
第一个,.//和//的区别:
例如下面这个xpath表达式://div[.//a[text()=‘SELENIUM’]]/ancestor::div[@class=‘rt-grid-2 rt-omega’]/following-sibling::div
其中第一个div后面的[.//a[text()=‘SELENIUM’]]中的.//是什么意思呢,平时我们用的不都是//吗?这里之前我也没太注意,但后来专门看了一下,原来//是指从全文上下文中搜索//后面的节点,而.//则是指从前面的节点的子节点中进行查找。比如上面的例子就代表从任意div中查找其子节点是a元素,并且文本为SELENIUM的a元素。
第二个,凡是用text()的地方均可以直接用.来进行表示,例如a[text()=‘SELENIUM’]和a[.=‘SELENIUM’]是等价的。
欢迎大家关注我的公众号:Python极客栈