菜单

开源二个IE下获得XPath小工具,支持32/陆10个人

2019年5月2日 - jQuery

XPath是3个好工具

2014/02/23 · CSS · 3
评论
·
CSS

本文由 伯乐在线
杨帅
翻译。未经许可,禁止转发!
英文出处:rapgenius。接待参加翻译组

自己首先次接触XPath是在200七年,但多年来才开首对它发出兴趣。以前在大部场地下自身都会尽量防止使用它,而当自个儿只得尝试利用它时,每便皆以败诉告终。那时XPath对自家的话并从未什么样意义。

而是后来本人遇上了一个独特的分析难点(对CSS接纳器来讲过于复杂,而用手工业代码的话又过分轻便),于是本人说了算再尝试3回XPath。令小编深感欢跃的是,那的确行得通,而且很有用。

以下是自己的亲身经历

背景是早就友情扶助了测试组一小段时日,发掘他们选拔selenium做页面包车型地铁自动化测试,供给选拔X帕特h,但IE下未有获得XPath的工具,只还好Firefox和chrome下获得,步骤还相比艰辛。而且某个页面在chrome和ie生成的代码的不平等的,所以chrome下获得的xpath,到ie下就无法专门的学业,只可以本身在ie下查看页面成分协和写xpath,难受而且效能低下。

本人遇见的主题素材

假定你管理1个乐章网站,为了维持1致的读书体验,你要采访每行歌词的第二个单词。假如歌词使用纯文本格式保存,那么能够一向用下边包车型地铁代码来落成。

JavaScript

lyrics.gsub!(/^./) { |character| character.upcase }

1
lyrics.gsub!(/^./) { |character| character.upcase }

只是只要歌词被保存肯html格式就从不及此简单了,因为dom结构本人并未”行”的定义,所以未有章程使用三个大致的正则表明式来识别行。

之所以大家要做的首先件业务是概念什么是dom结构中的“行的起源”,上边是三个大约的例证:

就像上边那样:

XHTML

<p>This is the beginning of a line.<br>This is
too.</p>

1
<p>This is the beginning of a line.<br>This is too.</p>

唯独除却大家或者还要管理嵌套的行内成分:

XHTML

<p><em>This</em> is the beginning of a line.
<strong>This is not.</strong></p>

1
<p><em>This</em> is the beginning of a line. <strong>This is not.</strong></p>

于是乎“大发慈悲”,本人花了一天左右(开辟加调节和测试)写了那款小工具,弥补了IE下未有赢得XPath工具的空缺。一齐头用Delphi做的,但无能为力支撑63位,于是又用C#写了1回,能够支撑32/64个人了。这一次开源的正是C#的。

例行的化解方案

本人想到的首先个减轻办法是用Ruby写二个艺术来围观dom中享有有关的一些并递归寻觅装有符合条件的节点。个中使用了多少个轻量级的css采用器:

JavaScript

def each_new_line(document) document.css('p').each { |p|
yield first_text_node(p) } document.css('br').each { |br|
yield first_text_node(br.next) } end def first_text_node(node) if
node.nil? then nil elsif node.text? then node elsif node.children.any?
then first_text_node(node.children.first) end end

1
2
3
4
5
6
7
8
9
10
11
def each_new_line(document)
  document.css(&#039;p&#039;).each { |p| yield first_text_node(p) }
  document.css(&#039;br&#039;).each { |br| yield first_text_node(br.next) }
end
 
def first_text_node(node)
  if node.nil? then nil
  elsif node.text? then node
  elsif node.children.any? then first_text_node(node.children.first)
  end
end

那是一个比较客观的减轻方案,不过1一行的代码就像有点儿长。有点儿杀鸡用牛刀的认为,仅仅为了拿走dom的节点而用上Ruby的迭代器和标准语句以为有个别犯不上。应该有更加好的章程呢?

工具发出了,自动化测试人士一下子就用起来了,大家都上报好用简短方便,软件又小巧唯有80k,不像有个别工具运行都要半分钟。短期下载量就有150+,使用人口我估计得有200人啊。(作者都存疑厂商有未有200个自动化测试人士)。

到底聊起正题了(XPath)

X帕特h有须臾间多少个原因轻便令人纳闷。第二点是网络大约从不得以参考的东西(W3Schools!就绝不想了)。RFC已经是自己找到的最棒的文书档案了。

第三点是XPath看上去有个别像CSS。方法名里就有“path”,所以自身延续假若X帕特h的表明式中的
/ 和CSS采纳器中的 > 是一个乐趣。

JavaScript

document.xpath('//p/em/a') == document.css('p > em
> a')

1
document.xpath(&#039;//p/em/a&#039;) == document.css(&#039;p &gt; em &gt; a&#039;)

实则,XPath说明式包蕴了多数简写,假如大家想要弄驾驭下面代码运维时到底发生了如何就非得要弄掌握这么些简写。上面是用全拼写出来的1模同样的表明式:

JavaScript

/descendant-or-self::node()/child::p/child::em/child::a/

1
/descendant-or-self::node()/child::p/child::em/child::a/

以此XPath表达式和方面包车型大巴CSS选拔器的效应是一样的,但并不像自个儿事先要是的那样。叁个XPath表明式是由叁个或八个被
/ 分割的确定地点步(location steps)组成。表达式中的第三个 /
代表了文书档案(document)的根节点。每种定位步都申明了已经被相称的节点并转达一下3条新闻:

自身想从近期的职位移动到哪?

答案是轴(Axis),是可选的。私下认可的轴是child,表示“当前被入选节点的全数子节点”。在上头的例子中,descendant-or-self是第3个定位部的轴,表示“全体当前被选中的节点和他们有所的子节点”。超越四陆%XPath标准中定义的轴都有像“descendant-or-self”那样的语义化的名字。

本人想要选用如何品种的节点?

选拔的剧情是由节点测试来内定的,那也是各种定位步中不可缺点和失误的有些。在大家此前的事例中,node()相称的是整个品类;text()相称到的是文本节点;element()只可以协作到成分,并必须指明节点名称(像p,em等),节点名称必填。

可能扩张额外的过滤器吗?

或是我们只想采用当前享有节点的率先个子成分或只想选则有href属性的<a>标签。对于此类断言(assertion),我们能够应用谓词(predicates)依照额外的遍历树(additional
tree
traversals)来过滤出符合条件的节点。那样我们就足以依据那个节点的质量(children,
parents, or siblings)来过滤出符合条件的节点。

大家的事例中绝非谓词,今后让大家来加八个只非常有href属性的<a>标签:

JavaScript

/descendant-or-self::node()/child::p/child::em/child::a[attribute::href]

1
/descendant-or-self::node()/child::p/child::em/child::a[attribute::href]

固然谓词看上去很像一个括号中的定位步,可是谓词中的“节点测试(node
test)”部分有比定位步中的节点测试越来越多的效劳。

不料本人三个开拓人士,居然在测试人士里面昙花1现闪亮了一把,造化弄人啊。那个软件还证实了一个事情,对用户切实有用的东西是不太需求宣传的。。。

换2个角度来看XPath

与一个加强型的CSS接纳器比较,XPath与JQuery的有益更相像。举例,我们得以把此前的X帕特h表明式换来JQuery的花样:

JavaScript

$(document).find(‘*’). children(‘p’). children(’em’).
children(‘a’).filter(‘[href]’)

1
2
3
4
$(document).find(‘*’).
  children(‘p’).
  children(’em’).
  children(‘a’).filter(‘[href]’)

地点的代码中,我们用到的JQuery的艺术与轴的效益是相同的:

JavaScript

.children()也正是轴中的child,.find()相当于descendant。

1
.children()相当于轴中的child,.find()相当于descendant。

JQuery方法中的选拔器相当于X帕特h中的节点测试,只可惜jQuery不容许选择文本节点。

jQuery中的.filter()方法也便是XPath中的谓词,.children(’em’)的效果是合营全数相称到的<p>标签中的全体<em>子成分。那样看来,XPah要比jQuery强大得多。

 

让大家回去识别行首的标题

近年来大家对XPath的干活原理已经有了深深的打听,上边来用它消除以前涉嫌的主题材料。首先我们先把难题简化一下,只寻觅每段的第1个公文节点:

JavaScript

/descendant-or-self::node()/child::p/child::text()[position()=1]

1
/descendant-or-self::node()/child::p/child::text()[position()=1]

地方的代码的效果依次是:

只顾position() function
在代码中意味着的是各类<p>中的第一个文本子节点而不是全部文书档案中的第3个<p>的文本子节点。

接下去,为了找到<p>中被嵌套得很深的文本节点,大家把child换到descendant

JavaScript

/descendant-or-self::node()/child::p/descendant::text()[position()=1]

1
/descendant-or-self::node()/child::p/descendant::text()[position()=1]

接下去是识别换行的主题素材,首先大家给那壹长串代码折下行(因为太长了),XPath是同意这样做的。参预换行的辨认后,代码如下:

JavaScript

/descendant-or-self::node()/ child::br/
following-sibling::node()[position=1]/
descendant-or-self::text()[position()=1]

1
2
3
4
/descendant-or-self::node()/
child::br/
following-sibling::node()[position=1]/
descendant-or-self::text()[position()=1]

每1行代码的意思分别是:

那样1来大家就足以而且选出<p>如月<br>后的新的一条龙。下边大家上述的代码合并成一个表明式:

JavaScript

(/descendant-or-self::node()/child::p|
/descendant-or-self::node()/child::br/following-sibling::node()[position=1])/
descendant-or-self::text()[position()=1]

1
2
3
(/descendant-or-self::node()/child::p|
/descendant-or-self::node()/child::br/following-sibling::node()[position=1])/
descendant-or-self::text()[position()=1]

末段大家把简写替换进去:

JavaScript

(//p|//br/following-sibling::node()[position=1])/
descendant-or-self::text()[position=1]

1
2
(//p|//br/following-sibling::node()[position=1])/
descendant-or-self::text()[position=1]

诸如此类我们就把三个错落有致的概念用三个轻巧易行的表明式表示出来了。如若大家想出席越多的对行的操作,只供给往实现相称的代码中参加更加多的成分名称就能够了。

动用很简短,直接拖动左下角鼠标到IE查看就可以。仍是能够查阅IE密码框里面包车型地铁密码。公司内部有自动化测试的人手提出转给他们(特别是测试的MM
^_^),他们会感激你的。代码已经开源,对代码风乐趣的能够去Github上看看。都以些windows代码,才能含量不高,windows的事物便是调和相比耗费时间。

大家到底能从中获得怎么样?

既然如此大家能用绝对易懂的Ruby来促成为啥还要选拔XPath呢?

大部情况下,Ruby是用来编排高层代码的,比如商业逻辑,整合应用组件,描述复杂的天地模型。从中能够看出最佳的Ruby代码是用来叙述意图而非用于落到实处。所以用Ruby来做一些低等次或与行使无关的事情(遍历dom树来找钦点属性的节点)令人蛋疼。

XPath的里边二个优势是它的快慢:X帕特h的遍历是因此libxml落成的,而原生代码的进程是13分快的。对于自个儿上边举的事例,与Ruby的兑现比较,XPath实际上要慢得多。笔者猜导致这么些场所包车型大巴来由是对此<br>标签的下二个因素的搜寻。因为在这几个动作中实际是先筛选出了<br>前面包车型客车全体与之同级的成分然后才过滤出里面包车型客车首先个。

故而X帕特h快慢与否取决于你的使用格局,可是左手有点儿难。那是二个尤其用来让您利用轻松的惯用表达式来遍历dom的工具。

赞 收藏 3
评论

 

有关我:杨帅

图片 1

(博客园博客园:@JAVA程序员杨帅)

个人主页
·
作者的文章

图片 2

点击这里下载IEXPth

 

 图片 3图片 4

图片 5

图片 6

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图