黃聰:HtmlAgilityPack中SelectSingleNode的XPath和CSS選擇器


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結合起來使用.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM