Xpath中关于部分常用轴表达式使用总结

我们在自动化测试中会经常使用到xpath来进行对象的选择。之前我写过的一篇关于自动化测试对象定位的八种常用方式中,也介绍了一些xpath的基本表达式。但有些比较特殊的情况中,仅靠这些比较基本的xpath表达式还不够灵活,所以今天继续介绍几种比较常用的基于“轴(Axes)”的表达式。

本文中的示例HTML代码为http://www.guru99.com,代码使用的区域为如下图所示,大家可以在该页面中对照试验代码:

![这里写图片描述](https://img-blog.csdn.net/20170129220332098?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcWluZ2NodW5qdW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
  • following::与preceding::
    following 指在当前上下文节点之后的所有节点,除属性节点和命名空间节点之外。
    例如,我们要在示例代码段中查找“Learn SQL”之后含有“Learn Python”内容的a节点,表达式可以这样写(请在chrome的console控制台中进行试验):

$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::基本类似,前者表示查找的目标在当前节点之前,后者表示查找的目标在当前节点之后,仅此而已。在实际运用时,需要根据实际情况进行选择。

  • following-sibling::和preceding-sibling
    following-sibling和following的区别是,following-sibling只会标识出当前上下文节点之后的兄弟节点,而不包含其他子节点。例如,我们还是要在示例代码段中查找“Learn SQL”之后含有“Learn Python”内容的a节点,但这次需要用following-sibling来查找,该如何写呢?我们先来看看源码,由于//a[contains(text(), ‘Learn SQL’)]这个a节点根本就没有兄弟节点,所以我们不能直接利用following-sibling来定位其他a节点,必须想点曲线救国的方法。经过观察,我们发现我们最终要找的a标签是Learn SQL的父标签li的兄弟节点下面的子节点,所以现在表达式应该像下面这样写:

$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完全类似,就不再赘述。

  • parent::和child::
    parent::可指定要查找的当前节点的直接父节点,例如,父节点是个div,即可写成parent::div,如果像上面那个例子那样是个li元素,则可写成parent::li。如果要找的元素不是直接父元素,则不可使用parent,可使用ancestor,代表父辈、祖父辈等节点。同样,child::表示直接子节点元素,所以上面那个例子也可以写成下面这个样子,效果一样:

$x("//a[contains(text(), ‘Learn SQL’)]/parent::li/following-sibling::li/child::a[contains(text(), ‘Learn Python’)]")

  • ancestor::和descendant::
    ancestor::可以查找当前上下文节点的父级或父级的父级,descendant::则正好相反,查找子级或子级的子级。例如,我们现在要求通过Learn SQL来查找标题Web的节点,xpath就可以这样写了:

$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极客栈

Xpath中关于部分常用轴表达式使用总结_第1张图片

你可能感兴趣的:(自动化测试工具)