国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

XPath 是一個(gè)好工具

Ilikewhite / 772人閱讀

摘要:一個(gè)表達(dá)式是由一個(gè)或多個(gè)被分割的定位步組成。對(duì)于此類斷言,我們可以使用謂詞根據(jù)額外的遍歷樹(shù)來(lái)過(guò)濾出符合條件的節(jié)點(diǎn)。所以用來(lái)做一些低水平或與應(yīng)用無(wú)關(guān)的事情遍歷樹(shù)來(lái)找指定屬性的節(jié)點(diǎn)讓人蛋疼。這是一個(gè)專門用來(lái)讓你使用簡(jiǎn)潔的慣用表達(dá)式來(lái)遍歷的工具。

  

編者注: XPath 即為XML路徑語(yǔ)言(XML Path Language),它是一種用來(lái)確定XML文檔中某部分位置的語(yǔ)言。
XPath基于XML的樹(shù)狀結(jié)構(gòu),提供在數(shù)據(jù)結(jié)構(gòu)樹(shù)中找尋節(jié)點(diǎn)的能力。起初XPath的提出的初衷是將其作為一個(gè)通用的、介于XPointer與XSL間的語(yǔ)法模型。但是XPath很快的被開(kāi)發(fā)者采用來(lái)當(dāng)作小型查詢語(yǔ)言。

我第一次接觸XPath是在2007年,但最近才開(kāi)始對(duì)它產(chǎn)生興趣。以前在大多數(shù)情況下我都會(huì)盡量避免使用它,而當(dāng)我不得不嘗試使用它時(shí),每次都以失敗告終。那時(shí)XPath對(duì)我來(lái)說(shuō)并沒(méi)有什么意義。

但是后來(lái)我遇到了一個(gè)特殊的解析問(wèn)題(對(duì)CSS選擇器來(lái)說(shuō)過(guò)于復(fù)雜,而用手工代碼的話又過(guò)于簡(jiǎn)單),于是我決定再嘗試一次XPath。令我感到驚喜的是,這的確行得通,而且很有用。

以下是我的親身經(jīng)歷

我遇到的問(wèn)題

假設(shè)你管理一個(gè)歌詞網(wǎng)站,為了維持一致的閱讀體驗(yàn),你要收集每行歌詞的第一個(gè)單詞。如果歌詞使用純文本格式保存,那么可以直接用下面的代碼來(lái)實(shí)現(xiàn)。

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

但是如果歌詞被保存肯html格式就沒(méi)有這么簡(jiǎn)單了,因?yàn)閐om結(jié)構(gòu)本身并沒(méi)有”行”的概念,所以沒(méi)有辦法使用一個(gè)簡(jiǎn)單的正則表達(dá)式來(lái)識(shí)別行。

所以我們要做的第一件事情是定義什么是dom結(jié)構(gòu)中的“行的起點(diǎn)”,下面是兩個(gè)簡(jiǎn)單的例子:

標(biāo)簽中第一個(gè)文本節(jié)點(diǎn)


后面的第一個(gè)文本節(jié)點(diǎn)
就像下面這樣:

This is the beginning of a line.This is too.

但是除此之外我們可能還要處理嵌套的行內(nèi)元素:

This is the beginning of a line. This is not.

常規(guī)的解決方案

我想到的第一個(gè)解決方法是用Ruby寫一個(gè)方法來(lái)掃描dom中所有相關(guān)的部分并遞歸找出所有符合條件的節(jié)點(diǎn)。其中用到了幾個(gè)輕量級(jí)的css選擇器:

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

這是一個(gè)比較合理的解決方案,但是11行的代碼似乎有點(diǎn)兒長(zhǎng)。有點(diǎn)兒殺雞用牛刀的感覺(jué),僅僅為了獲得dom的節(jié)點(diǎn)而用上Ruby的迭代器和條件語(yǔ)句感覺(jué)有點(diǎn)兒犯不上。應(yīng)該有更好的辦法吧?

終于說(shuō)到正題了(XPath)

XPath有一下幾個(gè)原因容易讓人困惑。第一點(diǎn)是網(wǎng)上幾乎沒(méi)有可以參考的東西(W3Schools!就不用想了)。RFC已經(jīng)是我找到的最好的文檔了。

第二點(diǎn)是XPath看上去有點(diǎn)兒像CSS。方法名里就有“path”,所以我總是假設(shè)XPath的表達(dá)式中的 / 和CSS選擇器中的 > 是一個(gè)意思。

document.xpath("http://p/em/a") == document.css("p > em > a")

其實(shí),XPath表達(dá)式包含了許多簡(jiǎn)寫,如果我們想要弄清楚上面代碼運(yùn)行時(shí)究竟發(fā)生了什么就必須要弄清楚這些簡(jiǎn)寫。下面是用全拼寫出來(lái)的相同的表達(dá)式:

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

這個(gè)XPath表達(dá)式和上面的CSS選擇器的作用是一樣的,但并不像我之前假設(shè)的那樣。一個(gè)XPath表達(dá)式是由一個(gè)或多個(gè)被 / 分割的定位步(location steps)組成。表達(dá)式中的第一個(gè) / 代表了文檔(document)的根節(jié)點(diǎn)。每個(gè)定位步都表明了已經(jīng)被匹配的節(jié)點(diǎn)并傳達(dá)一下三條信息:

我想從當(dāng)前的位置移動(dòng)到哪?

答案是軸(Axis),是可選的。默認(rèn)的軸是child,表示“當(dāng)前被選中節(jié)點(diǎn)的所有子節(jié)點(diǎn)”。在上面的例子中,descendant-or-self是第一個(gè)定位部的軸,表示“所有當(dāng)前被選中的節(jié)點(diǎn)和他們所有的子節(jié)點(diǎn)”。大部分XPath規(guī)范中定義的軸都有像“descendant-or-self”這樣的語(yǔ)義化的名字。

我想要選擇什么類型的節(jié)點(diǎn)?

選擇的內(nèi)容是由節(jié)點(diǎn)測(cè)試來(lái)指定的,這也是每個(gè)定位步中不可缺少的部分。在我們之前的例子中,node()匹配的是全部類型;text()匹配到的是文本節(jié)點(diǎn);element()只能匹配到元素,并必須指明節(jié)點(diǎn)名稱(像p,em等),節(jié)點(diǎn)名稱必填。

可能增加額外的過(guò)濾器嗎?

也許我們只想選擇當(dāng)前所有節(jié)點(diǎn)的第一個(gè)子元素或只想選則有href屬性的標(biāo)簽。對(duì)于此類斷言(assertion),我們可以使用謂詞(predicates)根據(jù)額外的遍歷樹(shù)(additional tree traversals)來(lái)過(guò)濾出符合條件的節(jié)點(diǎn)。這樣我們就可以根據(jù)這些節(jié)點(diǎn)的屬性(children, parents, or siblings)來(lái)過(guò)濾出符合條件的節(jié)點(diǎn)。

我們的例子中沒(méi)有謂詞,現(xiàn)在讓我們來(lái)加一個(gè)只匹配有href屬性的標(biāo)簽:

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

雖然謂詞看上去很像一個(gè)括號(hào)中的定位步,但是謂詞中的“節(jié)點(diǎn)測(cè)試(node test)”部分有比定位步中的節(jié)點(diǎn)測(cè)試更多的功能。

換一個(gè)角度來(lái)看XPath

與一個(gè)增強(qiáng)型的CSS選擇器相比,XPath與JQuery的便利更相似。例如,我們可以把之前的XPath表達(dá)式換成JQuery的形式:

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

上面的代碼中,我們用到的JQuery的方法與軸的作用是一樣的:

.children()相當(dāng)于軸中的child,.find()相當(dāng)于descendant。

JQuery方法中的選擇器相當(dāng)于XPath中的節(jié)點(diǎn)測(cè)試,只可惜jQuery不允許選擇文本節(jié)點(diǎn)。

jQuery中的.filter()方法相當(dāng)于XPath中的謂詞,.children(‘em’)的作用是匹配所有匹配到的

標(biāo)簽中的所有子元素。這樣看來(lái),XPah要比jQuery強(qiáng)大得多。

讓我們回到識(shí)別行首的問(wèn)題

現(xiàn)在我們對(duì)XPath的工作原理已經(jīng)有了深入的了解,下面來(lái)用它解決之前提到的問(wèn)題。首先我們先把問(wèn)題簡(jiǎn)化一下,只尋找每段的第一個(gè)文本節(jié)點(diǎn):

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

上面的代碼的作用依次是:

尋找文檔中的所有節(jié)點(diǎn)

尋找這些節(jié)點(diǎn)的所有為

的子節(jié)點(diǎn)

尋找這些

的文本子節(jié)點(diǎn)

只保留這些節(jié)點(diǎn)中符合條件的第一個(gè)元素

注意position() function 在代碼中表示的是每個(gè)

中的第一個(gè)文本子節(jié)點(diǎn)而不是整個(gè)文檔中的第一個(gè)

的文本子節(jié)點(diǎn)。

接下來(lái),為了找到

中被嵌套得很深的文本節(jié)點(diǎn),我們把child換成descendant

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

接下來(lái)是識(shí)別換行的問(wèn)題,首先我們給這一長(zhǎng)串代碼折下行(因?yàn)樘L(zhǎng)了),XPath是允許這樣做的。加入換行的識(shí)別后,代碼如下:

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

每一行代碼的意思分別是:

找到所有節(jié)點(diǎn)

找到到這些節(jié)點(diǎn)的
子節(jié)點(diǎn)

找到這些
的下一個(gè)同級(jí)節(jié)點(diǎn)

如果上面取到的不是文本節(jié)點(diǎn),則取它們的子節(jié)點(diǎn)中的第一個(gè)文本節(jié)點(diǎn)

這樣一來(lái)我們就可以同時(shí)選出

中和
的新的一行。下面我們以上的代碼合并成一個(gè)表達(dá)式:

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

最后我們把簡(jiǎn)寫替換進(jìn)去:

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

這樣我們就把一個(gè)復(fù)雜的概念用一個(gè)簡(jiǎn)單的表達(dá)式表示出來(lái)了。如果我們想加入更多的對(duì)行的操作,只需要往實(shí)現(xiàn)匹配的代碼中加入更多的元素名稱就可以了。

我們究竟能從中獲得什么?

既然我們能用相對(duì)易懂的Ruby來(lái)實(shí)現(xiàn)為什么還要選擇XPath呢?

大多數(shù)情況下,Ruby是用來(lái)編寫高水平代碼的,例如商業(yè)邏輯,整合應(yīng)用組件,描述復(fù)雜的領(lǐng)域模型。從中可以看出最好的Ruby代碼是用來(lái)描述意圖而非用于實(shí)現(xiàn)。所以用Ruby來(lái)做一些低水平或與應(yīng)用無(wú)關(guān)的事情(遍歷dom樹(shù)來(lái)找指定屬性的節(jié)點(diǎn))讓人蛋疼。

XPath的其中一個(gè)優(yōu)勢(shì)是它的速度:XPath的遍歷是通過(guò)libxml實(shí)現(xiàn)的,而原生代碼的速度是非常快的。對(duì)于我上面舉的例子,與Ruby的實(shí)現(xiàn)相比,XPath實(shí)際上要慢得多。我猜導(dǎo)致這個(gè)情況的原因是對(duì)于
標(biāo)簽的下一個(gè)元素的查找。因?yàn)樵谶@個(gè)動(dòng)作中實(shí)際上是先篩選出了
后面的所有與之同級(jí)的元素然后才過(guò)濾出其中的第一個(gè)。

所以XPath快慢與否取決于你的使用方式,但是上手有點(diǎn)兒難。這是一個(gè)專門用來(lái)讓你使用簡(jiǎn)潔的慣用表達(dá)式來(lái)遍歷dom的工具。

原文:XPath is actually pretty useful once it stops being confusing
轉(zhuǎn)載于: 伯樂(lè)在線 - 楊帥

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/110880.html

相關(guān)文章

  • XPath 一個(gè)工具

    摘要:一個(gè)表達(dá)式是由一個(gè)或多個(gè)被分割的定位步組成。對(duì)于此類斷言,我們可以使用謂詞根據(jù)額外的遍歷樹(shù)來(lái)過(guò)濾出符合條件的節(jié)點(diǎn)。所以用來(lái)做一些低水平或與應(yīng)用無(wú)關(guān)的事情遍歷樹(shù)來(lái)找指定屬性的節(jié)點(diǎn)讓人蛋疼。這是一個(gè)專門用來(lái)讓你使用簡(jiǎn)潔的慣用表達(dá)式來(lái)遍歷的工具。 編者注: XPath 即為XML路徑語(yǔ)言(XML Path Language),它是一種用來(lái)確定XML文檔中某部分位置的語(yǔ)言。 XPat...

    codecraft 評(píng)論0 收藏0
  • Selenium+python親測(cè)爬蟲(chóng)工具爬取年度電影榜單

    摘要:介紹是一個(gè)用于應(yīng)用程序測(cè)試的工具,測(cè)試直接運(yùn)行在瀏覽器中,就像真正的用戶在操作一樣。支持的瀏覽器包括,,,,,等,它在的領(lǐng)域里的引用能使初學(xué)者大大的省去解析網(wǎng)頁(yè)中代加密的一些麻煩。 Selenium介紹 Selenium 是一個(gè)用于Web應(yīng)用程序測(cè)試的工具,Selenium測(cè)試直接運(yùn)行在瀏覽...

    Jiavan 評(píng)論0 收藏0
  • 軟件接口測(cè)試工具Jmeter使用核心詳解【建議收藏】

    用Jmeter做接口測(cè)試只需要掌握幾個(gè)核心功能就可以了。 并不一定要把它所有的功能都掌握,先掌握核心功能入行,然后再根據(jù)工作需要和職業(yè)規(guī)劃來(lái)學(xué)習(xí)更多的內(nèi)容。這篇文章在前面接口測(cè)試框架(測(cè)試計(jì)劃--->線程組--->請(qǐng)求--->查看結(jié)果樹(shù))的前提下,來(lái)介紹必須要掌握的幾個(gè)核心功能,力求用最短的時(shí)間取得最大的成果。 在前面的文章中我提到,用Jmeter做接口測(cè)試的核心是單接口測(cè)試的參數(shù)化和關(guān)聯(lián)接口測(cè)試...

    zoomdong 評(píng)論0 收藏0
  • 以后再有人問(wèn)你selenium什么,你就把這篇文章給他

    摘要:不同目標(biāo)的自動(dòng)化測(cè)試有不同的測(cè)試工具,但是任何工具都無(wú)不例外的需要編程的過(guò)程,實(shí)現(xiàn)源代碼,也可以稱之為測(cè)試腳本。 寫在最前面:目前自動(dòng)化測(cè)試并不屬于新鮮的事物,或者說(shuō)自動(dòng)化測(cè)試的各種方法論已經(jīng)層出不窮,但是,能夠在項(xiàng)目中持之以恒的實(shí)踐自動(dòng)化測(cè)試的團(tuán)隊(duì),卻依舊不是非常多。有的團(tuán)隊(duì)知道怎么做,做的還不夠好;有的團(tuán)隊(duì)還正在探索和摸索怎么做,甚至還有一些多方面的技術(shù)上和非技術(shù)上的舊系統(tǒng)需要重構(gòu)……...

    Keven 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<