1. 程式人生 > >document.evaluate的詳細用法--使用XPath查詢某些節點物件[z]

document.evaluate的詳細用法--使用XPath查詢某些節點物件[z]

http://m.blog.csdn.net/lemonsee/article/details/6925396

使用 Greasemonkey 時會遇到的功能最為強大的一個工具就是 evaluate 函式。通過使用XPath這種查詢語言,它可以用來尋找頁面中的元素,屬性和文字。

舉個例子來說,如果您想獲得某個頁面上的全部連結。您也許會想到使用document.getElementsByTagName('a');但是如果您還要繼續檢查是否每個連結都具有href屬性,因為<a>還可以用來作為錨名稱使用,這時,您需要使用Firefox內建的XPath 支援去獲取全部具有href屬性的<a>元素。

例子: 獲取頁面上的全部連結

var allLinks, thisLink;
allLinks = document.evaluate(
     '//a[@href]',
     document,
     null,
     XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
     null);
for (var i = 0; i < allLinks.snapshotLength; i++) {
     thisLink = allLinks.snapshotItem(i);
     // do something with thisLink
}
這裡,document.evaluate 是關鍵的部分。 它把 XPath 查詢語句作為一個字串,其它的引數稍後再做解釋。 這條 XPath   查詢語句可以找到全部具有href屬性的<a>元素,並將它們按照隨機的順序依次返回。(這就是說,第一個被返回的元素並一定也是頁面上的第一個這樣的元素。) 隨後,您就可以用 allLinks.snapshotItem(i) 函式訪問每一個元素。


XPath表示式所能做到的甚至會使您驚訝。請看下面這個例子,它獲取了全部具有title屬性的元素。


例子: 獲取全部具有title屬性的元素

var allElements, thisElement;
allElements = document.evaluate(
     '//*[@title]',
     document,
     null,
     XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
     null);
for (var i = 0; i < allElements.snapshotLength; i++) {
     thisElement = allElements.snapshotItem(i);
     switch (thisElement.nodeName.toUpperCase()) {
         case 'A':
             // this is a link, do something
             break;
         case 'IMG':
             // this is an image, do something else
             break;
         default:
             // do something with other kinds of HTML elements
     }
}

如果您已經引用了某個元素(例如上面的 thisElement),您就可以用 thisElement.nodeName 來替代它所對應的在   HTML 頁面中的標籤名稱。如果被訪問的這個頁面是以 text/html 的方式被伺服器執行, 那麼標籤名稱總是用大寫子母返回,不論它在原始頁面是如何定義的。 如果頁面是 application/xhtml+xml 方式的, 那麼標籤名稱就會以小寫子母返回。 不論哪種情況,我總是用   thisElement.nodeName.toUpperCase() 得到大寫的標籤名稱。  


這是另外一個 XPath 查詢,它返回了 div 中的一個特殊的類。


例子: 獲取 div 中的 sponsoredlink 類

var allDivs, thisDiv;
allDivs = document.evaluate(
     "//div[@class='sponsoredlink']",
     document,
     null,
     XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
     null);
for (var i = 0; i < allDivs.snapshotLength; i++) {
     thisDiv = allDivs.snapshotItem(i);
     // do something with thisDiv
}
注意我在 XPath 查詢語句外使用了雙引號,這樣在語句內部就可以使用單引號。


在 document.evaluate 函式中有很多引數。第二個引數 (在前兩個例子中都是docoment) 可以是一個元素, XPath 查詢只返回包含在這個元素內的元素。所以,如果您已經引用了一個元素(比如, 通過 document.getElementById 或者 通過   document.getElementsByTagName 得到的陣列中的一個元素), 那麼您就可以限制查詢只返回這個元素的子元素。


第三個引數是對一個叫做 namespace resolver 函式的引用, 它只有在工作在 application/xhtml+xml 型別的頁面上的使用者指令碼中是有效的。即使您對它不是很瞭解也沒有關係,因為那種型別的頁面不是很多,您可能一次也遇不到。 如果您很想知道它是如何使用的,請參考   Mozilla XPath documentation (http://www-jcsu.jesus.cam.ac.uk/~jg307/mozilla/xpath-tutorial.html),那裡解釋了它的用法。


第四個引數是結果的返回方式。在前面的兩個例子中都使用了 XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, 它將結果以隨機的方式返回。我使用的幾乎全部都是這種方式,但是,出於某種原因,您想讓結果以它們在頁面上出現的順序返回,您可以使用   XPathResult.ORDERED_NODE_SNAPSHOT_TYPE 這種方式。 Mozilla XPath documentation (http://www-jcsu.jesus.cam.ac.uk/~jg307/mozilla/xpath-tutorial.html)還給出了另外的一些用例。


第五個引數用來合併兩次 XPath 查詢的結果。 在獲得第一次呼叫 document.evaluate 得到的結果之後,它將兩次查詢的結果一起返回。在前面的兩個例子中,這個引數都用了null,這意味著我們只想獲得本次查詢的結果。


現在您明白了嗎?XPath 既可以很簡單,也可以很難,這取決於您要如何使用它。在此我強烈推薦您儘快去閱讀 this excellent XPath tutorial (http://www.zvon.org/xxl/XPathTutorial/General/examples.html),從而瞭解更多的 XPath 語法。至於 document.evaluate 函式的其它引數, 我幾乎從來不使用它們。事實上,您可以自己定義一個函式來封裝它們。


例子: 自定義的 xpath 函式

function xpath(query) {
     return document.evaluate(query, document, null,
         XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
}

在定義了這個函式之後,您就可以呼叫 xpath('//a[@href]') 來獲得某個頁面上的全部連結, 或者呼叫 xpath('//* [@title]') 來獲得具有 title 屬性的元素。您仍然需要通過 snapshotItem 函式來訪問結果中的每一項,這個函式的型別並不是一個規則的Javascript陣列。