您好,欢迎访问一九零五行业门户网

XPath和CSS选择器_html/css_WEB-ITnose

[译]xpath和css选择器
原文:http://ejohn.org/blog/xpath-css-selectors
最近,我做了很多工作来实现一个同时支持xpath和css 3的解析器,令我惊讶的是:它们俩在某些方面上非常相似,而在另一些方面上又完全不同.不同的地方有,css是用来配合html工作的,可以使用#id来根据id获取元素,以及使用.class来根据class获取元素.这些用xpath实现的话都不会那么简洁,反过来呢,xpath可以使用..来返回到dom树的上层节点中,还可以使用foo[bar]来获取到一个拥有bar子元素的foo元素.css选择器完全做不到这些,总结一下就是,和xpath比起来,css选择器通常都比较短小,但可惜的是不够强大.
我认为将这两种选择器的写法做一个比较是很有价值的.
目标 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元素
无法实现 //p[a]
下一个兄弟元素 p + * //p/following-sibling::*[0]
从语法上看,我非常惊讶这两种选择器在某些情况下的相似性,尤其是'>'和'/'两者之间.虽然他们并不总是有着相同的功能(xpath中要取决于正在使用的轴),但通常情况下他们指的都是某个父元素的子元素.还有,空白符' '和'//'都意味着当前元素的所有后代元素.最后是星号'*',类似于通配符,表示所有元素,而不管是哪种标签名.
1 这个写法其实不正确,因为它不光会匹配到我们想要的'foo bar',还会意外的匹配到'foobar'.正确的写法可能会非常复杂,可能会需要用到多个表达式才能完成.
下面是译者注: 上表中错误的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',可能有四种情况,列出表来是这样的:
class=foo //*[@class='foo'] class属性只有一个值foo
class=foobar foo bar //*[@class=' foo '] class属性值中,foo在其他两边的值的中间
class=foo bar
//*[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 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实现了,它会变的更加强大.
其它类似信息

推荐信息