代码改变世界

By.Xpath快速定位页面元素常用方法

2017-07-16 01:07  清风软件测试开发  阅读(3324)  评论(0编辑  收藏  举报

先看一看xpath的语法

我们将在下面的例子中使用这个 XML 文档。

<?xml version="1.0" encoding="ISO-8859-1"?>

<bookstore>

<book>
  <title lang="eng">Harry Potter</title>
  <price>29.99</price>
</book>

<book>
  <title lang="eng">Learning XML</title>
  <price>39.95</price>
</book>

</bookstore>

 

选取节点

XPath 使用路径表达式在 XML 文档中选取节点。节点是通过沿着路径或者 step 来选取的。

下面列出了最有用的路径表达式:

表达式描述
nodename 选取此节点的所有子节点。
/ 从根节点选取。
// 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
. 选取当前节点。
.. 选取当前节点的父节点。
@ 选取属性。

实例

在下面的表格中,我们已列出了一些路径表达式以及表达式的结果:

路径表达式结果
bookstore 选取 bookstore 元素的所有子节点。
/bookstore

选取根元素 bookstore。

注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径!

bookstore/book 选取属于 bookstore 的子元素的所有 book 元素。
//book 选取所有 book 子元素,而不管它们在文档中的位置。
bookstore//book 选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。
//@lang 选取名为 lang 的所有属性。

谓语(Predicates)

谓语用来查找某个特定的节点或者包含某个指定的值的节点。

谓语被嵌在方括号中。

实例

在下面的表格中,我们列出了带有谓语的一些路径表达式,以及表达式的结果:

路径表达式结果
/bookstore/book[1] 选取属于 bookstore 子元素的第一个 book 元素。
/bookstore/book[last()] 选取属于 bookstore 子元素的最后一个 book 元素。
/bookstore/book[last()-1] 选取属于 bookstore 子元素的倒数第二个 book 元素。
/bookstore/book[position()<3] 选取最前面的两个属于 bookstore 元素的子元素的 book 元素。
//title[@lang] 选取所有拥有名为 lang 的属性的 title 元素。
//title[@lang='eng'] 选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。
/bookstore/book[price>35.00] 选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。
/bookstore/book[price>35.00]/title 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。

选取未知节点

XPath 通配符可用来选取未知的 XML 元素。

通配符描述
* 匹配任何元素节点。
@* 匹配任何属性节点。
node() 匹配任何类型的节点。

实例

在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:

路径表达式结果
/bookstore/* 选取 bookstore 元素的所有子元素。
//* 选取文档中的所有元素。
//title[@*] 选取所有带有属性的 title 元素。

选取若干路径

通过在路径表达式中使用“|”运算符,您可以选取若干个路径。

实例

在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:

路径表达式结果
//book/title | //book/price 选取 book 元素的所有 title 和 price 元素。
//title | //price 选取文档中的所有 title 和 price 元素。
/bookstore/book/title | //price 选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素。

 

 

问题引入:

 用Selenium IDE录制后的脚本如下:

driver.findElement(By.name("pass")).clear();

driver.findElement(By.name("pass")).sendKeys("密 码");

driver.findElement(By.id("passwords")).clear();

driver.findElement(By.id("passwords")).sendKeys("123456");

回放的时候,页面非常难定位,需要很长时间才能找到密码框并输入密码,如果超时了找不到就会报错。

 

解决方案:

既然有时候能回放成功,有时候又找不到页面元素,那肯定是这个元素定位不够准确,所以在查找的时候会消耗很长时间,那么通过xpah定位是否可以?

 

Xpath查找元素对象时有这样一种定位方式,即通过//定位,详情请参考:http://www.w3school.com.cn/xpath/xpath_syntax.asp

//

从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。

比如这里密码框是输入框input,想要查找input的位置可以通过//input来实现,如果只是//input则可能会定位到多个input元素,此时就需要通过键值对更精确的定位,语法就是//input[@key=value],即://input[@name='pass']

 

driver.findElement(By.xpath("//input[@name='pass']")).clear();

driver.findElement(By.xpath("//input[@name='pass']")).sendKeys("密 码");

driver.findElement(By.xpath("//input[@id= passwords]")).clear();

driver.findElement(By.xpath("//input[@id= passwords]")).sendKeys("123456");

重新回放,时间仍然很长,看来通过一个元素键值对定位是不可靠的,那能不能通过多个元素呢?就跟QTP中的高级描述性编程一样。那xpath的语法是什么,多个元素键值对怎么连接到一起呢?

 

首先查找name=pass的这个元素的另外一个元素键值对:class= textfild,用这两个定位一下试试看。

driver.findElement(By.xpath("//input[@name='pass' and @class=’ textfild’]")).clear();

driver.findElement(By.xpath("//input[@name='pass' and @class=’ textfild’]")).sendKeys("密 码");

driver.findElement(By.xpath("//input[@id= passwords and @class=’ textfild required’]")).clear();

driver.findElement(By.xpath("//input[@id=passwords and @class=’textfild required’]")).sendKes(“12..”);

再回访,速度果然快了,很快便识别到了密码框的位置,并且进行了输入。

 

关于xpath 查找元素还可以通过contains(一个字符串查找函数)来实现,语法是

//input[contains(@id,vakue) and contains(@id,value)],此中的id和value就是定位input元素的键值对

 

例如:

//input[contains(@class,'textfild') andcontains(@name,'pass')]

 

那最后经过整合和简化,4句的代码可简化为以下两句

driver.findElement(By.xpath("//input[contains(@class,'textfild') andcontains(@name,'pass')]")).clear();

driver.findElement(By.xpath("//input[@id='passwords' and @class='textfild required' and @type='password']")).sendKeys("123456");

 

为什么能简化为2行呢,看上面的截图,其实一上来的时候密码框里有“密码”两个字,当鼠标移入密码框获取焦点以后,“密码”文字消失,用户就可以输入自己真正的密码。所以

driver.findElement(By.xpath("//input[@name='pass' and @class=’ textfild’]")).sendKeys("密 码");

这句话是我们不需要的。因为当密码框获取焦点以后,“密码”文字就消失了,所以下面的清空也没有必要存在了

driver.findElement(By.xpath("//input[@id= passwords and @class=’ textfild required’]")).clear();

这样,代码就简化了。