首頁 >後端開發 >php教程 >PHP DOM:使用XPATH

PHP DOM:使用XPATH

尊渡假赌尊渡假赌尊渡假赌
尊渡假赌尊渡假赌尊渡假赌原創
2025-02-26 09:07:16523瀏覽

PHP DOM: Using XPath

核心要點

  • XPath 是一種用於查詢 XML 文檔的語法,它提供了一種更簡單、更簡潔的方式來編寫功能,並減少了編寫查詢和過濾 XML 數據所需的代碼量。
  • XPath 查詢可以使用兩個函數執行:query()evaluate()。雖然兩者都執行查詢,但區別在於它們返回的結果類型,query() 返回 DOMNodeList,而 evaluate() 則盡可能返回類型化結果。
  • 使用 XPath 可以使代碼更簡潔、更高效。在比較測試中,使用純 XPath 的速度優勢相當明顯,XPath 版本比非 XPath 版本快約 10%。
  • PHP DOM 允許您使用自定義功能擴展標準 XPath 函數。這包括將 PHP 自身函數整合到 XPath 查詢中,以及註冊在 XPath 中使用的 PHP 函數。這擴展了 XPath 的功能,使其能夠執行更複雜的查詢。

本文將深入探討 XPath,包括其功能和在 PHP 中的實現方式。您將發現 XPath 可以大大減少編寫查詢和過濾 XML 數據所需的代碼量,並且通常也能提高性能。我將使用上一篇文章中相同的 DTD 和 XML 來演示 PHP DOM XPath 功能。為了快速回顧,以下是 DTD 和 XML 的樣子:

<code class="language-xml"><!DOCTYPE library [
  <!ELEMENT library (book*)>
  <!ELEMENT book (title, author, genre, chapter*)>
  <!ATTLIST book isbn ID #REQUIRED>
  <!ELEMENT title (#PCDATA)>
  <!ELEMENT author (#PCDATA)>
  <!ELEMENT genre (#PCDATA)>
  <!ELEMENT chapter (chaptitle,text)>
  <!ATTLIST chapter position NMTOKEN #REQUIRED>
  <!ELEMENT chaptitle (#PCDATA)>
  <!ELEMENT text (#PCDATA)>
]></code>
<code class="language-xml"><?xml version="1.0" encoding="utf-8"?>
<library>
  <book isbn="isbn1234">
    <title>A Book</title>
    <author>An Author</author>
    <genre>Horror</genre>
    <chapter position="first">
      <chaptitle>chapter one</chaptitle>
      <text></text>
    </chapter>
  </book>
  <book isbn="isbn1235">
    <title>Another Book</title>
    <author>Another Author</author>
    <genre>Science Fiction</genre>
    <chapter position="first">
      <chaptitle>chapter one</chaptitle>
      <text>Sit Dolor Amet...</text>
    </chapter>
  </book>
</library></code>

基本的 XPath 查詢

XPath 是一種用於查詢 XML 文檔的語法。最簡單的形式是定義您想要訪問的元素的路徑。使用上面的 XML 文檔,以下 XPath 查詢將返回所有存在的 book 元素的集合:

<code class="language-xpath">//library/book</code>

就是這樣。兩個正斜杠表示 library 是文檔的根元素,單個斜杠表示 book 是其子元素。非常簡單,不是嗎?但是,如果您想指定特定的書籍呢?假設您想返回任何由“An Author”撰寫的書籍。該 XPath 將是:

<code class="language-xpath">//library/book/author[text() = "An Author"]/..</code>

您可以在方括號中使用 text() 對節點的值執行比較,尾隨的“/..”表示我們想要父元素(即向上移動一個節點)。 XPath 查詢可以使用兩個函數之一執行:query()evaluate()。兩者都執行查詢,但區別在於它們返回的結果類型。 query() 將始終返回 DOMNodeList,而 evaluate() 則盡可能返回類型化結果。例如,如果您的 XPath 查詢是返回特定作者撰寫的書籍數量而不是實際的書籍本身,那麼 query() 將返回一個空的 DOMNodeListevaluate() 將直接返回數字,因此您可以立即使用它,而不必從節點中提取數據。

XPath 的代碼和速度優勢

讓我們做一個快速演示,返回特定作者撰寫的書籍數量。我們將首先查看一種可行的方法,但它不使用 XPath。這是為了向您展示如何在不使用 XPath 的情況下完成此操作,以及為什麼 XPath 如此強大。

<code class="language-xml"><!DOCTYPE library [
  <!ELEMENT library (book*)>
  <!ELEMENT book (title, author, genre, chapter*)>
  <!ATTLIST book isbn ID #REQUIRED>
  <!ELEMENT title (#PCDATA)>
  <!ELEMENT author (#PCDATA)>
  <!ELEMENT genre (#PCDATA)>
  <!ELEMENT chapter (chaptitle,text)>
  <!ATTLIST chapter position NMTOKEN #REQUIRED>
  <!ELEMENT chaptitle (#PCDATA)>
  <!ELEMENT text (#PCDATA)>
]></code>

下一種方法實現了相同的結果,但使用 XPath 來選擇僅由特定作者撰寫的書籍:

<code class="language-xml"><?xml version="1.0" encoding="utf-8"?>
<library>
  <book isbn="isbn1234">
    <title>A Book</title>
    <author>An Author</author>
    <genre>Horror</genre>
    <chapter position="first">
      <chaptitle>chapter one</chaptitle>
      <text></text>
    </chapter>
  </book>
  <book isbn="isbn1235">
    <title>Another Book</title>
    <author>Another Author</author>
    <genre>Science Fiction</genre>
    <chapter position="first">
      <chaptitle>chapter one</chaptitle>
      <text>Sit Dolor Amet...</text>
    </chapter>
  </book>
</library></code>

請注意,我們這次消除了 PHP 對作者值進行測試的需要。但是,我們還可以更進一步,使用 XPath 函數 count() 來計算此路徑的出現次數。

<code class="language-xpath">//library/book</code>

我們只需一行 XPath 就能檢索到所需信息,無需使用 PHP 執行費力的過濾。事實上,這是一種編寫此功能的更簡單、更簡潔的方法!請注意,在最後一個示例中使用了 evaluate()。這是因為函數 count() 返回類型化結果。使用 query() 將返回 DOMNodeList,但您會發現它是一個空列表。這不僅使您的代碼更簡潔,而且還具有速度優勢。我發現版本 1 的平均速度比版本 2 快 30%,但版本 3 比版本 2 快約 10%(比版本 1 快約 15%)。雖然這些測量結果會根據您的服務器和查詢而有所不同,但使用純 XPath 通常會帶來相當大的速度優勢,同時還能使您的代碼更易於閱讀和維護。

XPath 函數

XPath 可以使用相當多的函數,並且有很多優秀的資源詳細說明了可用的函數。如果您發現自己正在迭代 DOMNodeLists 或比較 nodeValues,您可能會發現一個 XPath 函數可以消除很多 PHP 代碼。您已經看到了 count() 函數的用法。讓我們使用 id() 函數來返回具有給定 ISBN 的書籍的標題。您需要使用的 XPath 表達式是:

<code class="language-xpath">//library/book/author[text() = "An Author"]/..</code>

請注意,此處要搜索的值用引號括起來並用空格分隔;無需使用逗號分隔術語。

<code class="language-php"><?php
public function getNumberOfBooksByAuthor($author) {
    $total = 0;
    $elements = $this->domDocument->getElementsByTagName("author");
    foreach ($elements as $element) {
        if ($element->nodeValue == $author) {
            $total++;
        }
    }
    return $total; // 修正:这里应该是 $total,而不是 $number
}
?></code>

在 XPath 中執行複雜函數相對簡單;訣竅是熟悉可用的函數。

在 XPath 中使用 PHP 函數

有時您可能會發現自己需要一些標準 XPath 函數無法提供的更強大的功能。幸運的是,PHP DOM 還允許您將 PHP 自身函數整合到 XPath 查詢中。讓我們考慮返回書籍標題中的單詞數量。最簡單的函數,我們可以這樣編寫方法:

<code class="language-xml"><!DOCTYPE library [
  <!ELEMENT library (book*)>
  <!ELEMENT book (title, author, genre, chapter*)>
  <!ATTLIST book isbn ID #REQUIRED>
  <!ELEMENT title (#PCDATA)>
  <!ELEMENT author (#PCDATA)>
  <!ELEMENT genre (#PCDATA)>
  <!ELEMENT chapter (chaptitle,text)>
  <!ATTLIST chapter position NMTOKEN #REQUIRED>
  <!ELEMENT chaptitle (#PCDATA)>
  <!ELEMENT text (#PCDATA)>
]></code>

但是,我們也可以將函數 str_word_count() 直接整合到 XPath 查詢中。為此需要完成幾個步驟。首先,我們必須使用 XPath 對象註冊一個命名空間。 XPath 查詢中的 PHP 函數以“php:functionString”開頭,然後是您想要使用的函數的名稱,括在括號中。此外,要定義的命名空間是 http://php.net/xpath。命名空間必須設置為這個;任何其他值都會導致錯誤。然後,我們需要調用 registerPHPFunctions(),它告訴 PHP 每當遇到以“php:”為命名空間的函數時,都應該由 PHP 處理它。調用函數的實際語法是:

<code class="language-xml"><?xml version="1.0" encoding="utf-8"?>
<library>
  <book isbn="isbn1234">
    <title>A Book</title>
    <author>An Author</author>
    <genre>Horror</genre>
    <chapter position="first">
      <chaptitle>chapter one</chaptitle>
      <text></text>
    </chapter>
  </book>
  <book isbn="isbn1235">
    <title>Another Book</title>
    <author>Another Author</author>
    <genre>Science Fiction</genre>
    <chapter position="first">
      <chaptitle>chapter one</chaptitle>
      <text>Sit Dolor Amet...</text>
    </chapter>
  </book>
</library></code>

將所有這些放在一起,得到 getNumberOfWords() 的以下重新實現:

<code class="language-xpath">//library/book</code>

請注意,您不需要調用 XPath 函數 text() 來提供節點的文本。 registerPHPFunctions() 方法會自動執行此操作。但是,以下同樣有效:

<code class="language-xpath">//library/book/author[text() = "An Author"]/..</code>

註冊 PHP 函數不僅限於 PHP 自帶的函數。您可以定義自己的函數並在 XPath 中提供這些函數。唯一的區別是,在定義函數時,您使用“php:function”而不是“php:functionString”。此外,只能提供函數本身或靜態方法。不支持調用實例方法。讓我們使用一個超出類範圍的常規函數來演示基本功能。我們將使用的函數將僅返回“喬治·奧威爾”的書籍。對於您希望包含在查詢中的每個節點,它必須返回 true

<code class="language-php"><?php
public function getNumberOfBooksByAuthor($author) {
    $total = 0;
    $elements = $this->domDocument->getElementsByTagName("author");
    foreach ($elements as $element) {
        if ($element->nodeValue == $author) {
            $total++;
        }
    }
    return $total; // 修正:这里应该是 $total,而不是 $number
}
?></code>

傳遞給函數的參數是 DOMElements 數組。函數負責迭代數組並確定要測試的節點是否應在 DOMNodeList 中返回。在此示例中,要測試的節點是 /book,我們使用 /author 來進行確定。現在我們可以創建方法 getGeorgeOrwellBooks()

<code class="language-php"><?php
public function getNumberOfBooksByAuthor($author) {
    $query = "//library/book/author[text() = '$author']/..";
    $xpath = new DOMXPath($this->domDocument);
    $result = $xpath->query($query);
    return $result->length;
}
?></code>

如果 compare() 是一個靜態方法,那麼您需要修改 XPath 查詢,使其讀取:

<code class="language-php"><?php
public function getNumberOfBooksByAuthor($author) {
    $query = "count(//library/book/author[text() = '$author']/..)";
    $xpath = new DOMXPath($this->domDocument);
    return $xpath->evaluate($query);
}
?></code>

事實上,所有這些功能都可以輕鬆地僅用 XPath 編寫,但該示例展示瞭如何擴展 XPath 查詢以使其更複雜。在 XPath 中無法調用對象方法。如果您發現需要訪問某些對象屬性或方法來完成 XPath 查詢,最好的解決方案是使用 XPath 完成您能做到的部分,然後根據需要使用任何對象方法或屬性處理生成的 DOMNodeList

總結

XPath 是一種在處理 XML 數據時減少代碼編寫量並加快代碼執行速度的好方法。雖然不是官方 DOM 規範的一部分,但 PHP DOM 提供的附加功能允許您使用自定義功能擴展標準 XPath 函數。這是一個非常強大的功能,隨著您對 XPath 函數的熟悉程度提高,您可能會發現自己越來越少地依賴它。

(圖片來自 Fotolia)

關於使用 XPath 的 PHP DOM 的常見問題解答 (FAQ)

什麼是 XPath,它如何在 PHP DOM 中使用?

XPath(XML 路徑語言)是一種查詢語言,用於從 XML 文檔中選擇節點。在 PHP DOM 中,XPath 用於遍歷 XML 文檔中的元素和屬性。它允許您通過多種方法找到並選擇 XML 文檔的特定部分,例如按名稱選擇節點、按其屬性值選擇節點或按其在文檔中的位置選擇節點。這使得它成為在 PHP 中解析和操作 XML 數據的強大工具。

如何創建 DOMXPath 的實例?

要創建 DOMXPath 的實例,您首先需要創建一個 DOMDocument 類的實例。獲得 DOMDocument 對像後,您可以通過將 DOMDocument 對像傳遞給 DOMXPath 構造函數來創建一個新的 DOMXPath 對象。這是一個示例:

<code class="language-xml"><!DOCTYPE library [
  <!ELEMENT library (book*)>
  <!ELEMENT book (title, author, genre, chapter*)>
  <!ATTLIST book isbn ID #REQUIRED>
  <!ELEMENT title (#PCDATA)>
  <!ELEMENT author (#PCDATA)>
  <!ELEMENT genre (#PCDATA)>
  <!ELEMENT chapter (chaptitle,text)>
  <!ATTLIST chapter position NMTOKEN #REQUIRED>
  <!ELEMENT chaptitle (#PCDATA)>
  <!ELEMENT text (#PCDATA)>
]></code>

如何使用 XPath 選擇節點?

您可以使用 DOMXPath 對象的 query() 方法選擇節點。 query() 方法將 XPath 表達式作為參數,並返回一個包含與表達式匹配的所有節點的 DOMNodeList 對象。例如:

<code class="language-xml"><?xml version="1.0" encoding="utf-8"?>
<library>
  <book isbn="isbn1234">
    <title>A Book</title>
    <author>An Author</author>
    <genre>Horror</genre>
    <chapter position="first">
      <chaptitle>chapter one</chaptitle>
      <text></text>
    </chapter>
  </book>
  <book isbn="isbn1235">
    <title>Another Book</title>
    <author>Another Author</author>
    <genre>Science Fiction</genre>
    <chapter position="first">
      <chaptitle>chapter one</chaptitle>
      <text>Sit Dolor Amet...</text>
    </chapter>
  </book>
</library></code>

這將選擇所有作為 <book></book> 元素子元素的 <title></title> 元素。

DOMXPath 中 query()evaluate() 方法的區別是什麼?

query()evaluate() 方法都用於評估 XPath 表達式。區別在於它們返回的結果類型。 query() 方法返回與 XPath 表達式匹配的所有節點的 DOMNodeList。另一方面,evaluate() 返回類型化結果,例如布爾值、數字或字符串,具體取決於 XPath 表達式。如果表達式結果為節點集,evaluate() 將返回 DOMNodeList。

如何在 XPath 查詢中處理命名空間?

要在 XPath 查詢中處理命名空間,您需要使用 registerNamespace() 方法將命名空間註冊到 DOMXPath 對象。此方法有兩個參數:前綴和命名空間 URI。註冊命名空間後,您可以在 XPath 查詢中使用前綴。例如:

<code class="language-xpath">//library/book</code>

如何使用 XPath 選擇屬性?

您可以使用 @ 符號後跟屬性名稱來選擇 XPath 中的屬性。例如,要選擇 <a></a> 元素的所有 href 屬性,您可以使用以下 XPath 表達式://a/@href

如何在 PHP DOM 中使用 XPath 函數?

XPath 提供了許多可以在 XPath 表達式中使用的函數。這些函數可用於操作字符串、數字、節點集等等。要在 PHP DOM 中使用 XPath 函數,只需在 XPath 表達式中包含該函數即可。例如,要選擇所有具有價格元素且值大於 30 的 <book></book> 元素,您可以使用 number() 函數,如下所示://book[number(price) > 30]

我可以在 PHP DOM 中將 XPath 與 HTML 文檔一起使用嗎?

是的,您可以在 PHP DOM 中將 XPath 與 HTML 文檔一起使用。但是,由於 HTML 不總是格式良好的 XML,因此在嘗試將 XPath 與 HTML 一起使用時可能會遇到問題。為了避免這些問題,您可以使用 DOMDocument 類的 loadHTML() 方法加載 HTML 文檔。此方法將解析 HTML 並糾正任何格式錯誤,允許您將 XPath 與生成的 DOMDocument 對像一起使用。

如何在 PHP DOM 中使用 XPath 時處理錯誤?

在 PHP DOM 中使用 XPath 時,可能會由於多種原因發生錯誤,例如 XPath 表達式格式錯誤或無法加載 XML 文檔。為了處理這些錯誤,您可以使用 libxml_use_internal_errors() 函數啟用用戶錯誤處理。此函數將導致 libxml 錯誤存儲在內部,允許您在代碼中處理它們。然後,您可以使用 libxml_get_errors() 函數檢索錯誤並根據需要處理它們。

我可以使用 PHP DOM 中的 XPath 修改 XML 文檔嗎?

雖然 XPath 本身不提供修改 XML 文檔的方法,但您可以將 XPath 與 DOM API 結合使用來修改 XML 文檔。您可以使用 XPath 選擇要修改的節點,然後使用 DOM API 提供的方法進行修改。例如,您可以使用 DOMNode 類的 removeChild() 方法刪除節點,或使用 DOMElement 類的 setAttribute() 方法更改屬性的值。

以上是PHP DOM:使用XPATH的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn