XPath和CSS选择器

[译]XPath和CSS选择器

原文:http://ejohn.org/blog/xpath-css-selectorscss


最近,我作了不少工做来实现一个同时支持XPath和CSS 3的解析器,令我惊讶的是:它们俩在某些方面上很是类似,而在另外一些方面上又彻底不一样.不一样的地方有,CSS是用来配合HTML工做的,可使用#id来根据ID获取元素,以及使用.class来根据class获取元素.这些用XPath实现的话都不会那么简洁,反过来呢,XPath可使用..来返回到DOM树的上层节点中,还可使用foo[bar]来获取到一个拥有bar子元素的foo元素.CSS选择器彻底作不到这些,总结一下就是,和XPath比起来,CSS选择器一般都比较短小,但惋惜的是不够强大.html

我认为将这两种选择器的写法作一个比较是颇有价值的.node

目标 CSS 3 XPath
全部元素 * //*
全部的P元素 p //p
全部的p元素的子元素 p > * //p/*
根据ID获取元素 #foo //*[@id='foo']
根据Class获取元素 .foo                                //*[contains(@class ,'foo')] 1
拥有某个属性的元素 *[title] //*[@title]
全部P元素的第一个子元素 p > *:first-child //p/*[0]

全部拥有子元素a的P元素git

没法实现 //p[a]
下一个兄弟元素 p + * //p/following-sibling::*[0]

从语法上看,我很是惊讶这两种选择器在某些状况下的类似性,尤为是'>'和'/'二者之间.虽然他们并不老是有着相同的功能(XPath中要取决于正在使用的轴),但一般状况下他们指的都是某个父元素的子元素.还有,空白符' '和'//'都意味着当前元素的全部后代元素.最后是星号'*',相似于通配符,表示全部元素,而不论是哪一种标签名.github


1 这个写法其实不正确,由于它不光会匹配到咱们想要的'foo bar',还会意外的匹配到'foobar'.正确的写法可能会很是复杂,可能会须要用到多个表达式才能完成.chrome

下面是译者注:

上表中错误的XPath:
浏览器

//*[contains(@class,'foo')]

我实现的写法是:函数

//*[@class='foo' or contains(@class,' foo ') or starts-with(@class,'foo ') or substring(@class,string-length(@class)-3)=' foo']

比起CSS的.foo,真的是好复杂,我来解释一下,一个元素的class属性中若是包含'foo',可能有四种状况,列出表来是这样的:google

class="foo" //*[@class='foo'] class属性只有一个值foo
class="foobar foo bar" //*[@class=' foo '] class属性值中,foo在其余两边的值的中间

class="foo bar"lua

//*[starts-with(@class,'foo ')] class属性值中,foo在最左边
class="bar foo" //*[substring(@class,string-length(@class)-3)=' foo'] class属性值中,foo在最右边,XPath1.0中没有ends-with函数,2.0有,如今浏览器实现的都是1.0

那么咱们能在网页开发中用上XPath吗?最初,jQuery是支持XPath选择器的,但后来,因为效率问题,jQuery放弃了对XPath的支持.恰好,谷歌在上个月发布了Wicked Good XPath,这是一个DOM Level 3 XPath规范的纯JavaScript实现,也是目前同类实现中最快的,咱们能够把这个脚本和jQuery结合起来使用.

jQuery.getScript("http://wicked-good-xpath.googlecode.com/files/wgxpath.install.js").success( () {        wgxpath.install();        jQuery.xpath =  elements = [];                        xpathResult = document.evaluate(xpath, document, , 6,  ( i = 0; i < xpathResult.snapshotLength; i++ jQuery(elements);

这样就能经过$.xpath()静态方法来选择元素了,该方法返回的也是一个jQuery对象,和使用$()没什么差异.本页面已经加载了这个脚本,你能够如今打开控制台试验一下$.xpath方法.

那咱们有了CSS选择器,为何还要用XPath呢,答案是:有些时候,XPath更强大一点.好比:

在上面John Resig总结的表中,有一个CSS没法实现的功能,就是查找包含某个子元素的父元素.的确,目前的CSS还没法实现,不过在将来CSS4的选择器中,将会有一个父选择器

E! > F    //注意,2011年的时候,父选择器的语法是$E > F,今年草案又改了.网上有些介绍CSS4选择器的博文仍是旧的,这里有一个能在CSS文件中使用父选择器的polyfill https://github.com/Idered/cssParentSelector

该选择器能够选取到那些包含子元素F的E元素.但即使之后实现了CSS4,稍微改变一下需求,查找那些包含后代元素F的E元素,CSS选择器又怎么写呢?应该是没什么办法实现.熟悉jQuery的朋友可能会说,jQuery里有:has伪类,能够这么写E:has(F),的确,若是使用jQuery自定义的过滤器,几乎任何需求均可以用遍历DOM的方法实现,但效率绝对会很低.而XPath就不同了,毕竟Firefox和chrome都已经实现了XPath的接口document.evaluate方法(Wicked Good XPath应该主要是努力在IE上实现统一的接口),速度确定比手动遍历DOM来的快.XPath的写法是这样的//E[.//F],怎么样,也挺简单明了的.

另外很重要的一点是,CSS原本是用于给HTML添加样式的,12种节点类型中,只有元素节点(nodetype等于1)才有样式这一说,所以,CSS选择器只能选取到页面中的元素节点,而XPath就不是了,它不光能够用在HTML中,还能够用在XML中,除了元素节点,而能够选择属性节点(//@*)或者文本节点(//text())等,若是将来XPath2.0实现了,它会变的更增强大.

相关文章
相关标签/搜索