PHP Conference Japan 2024

SimpleXMLElement::xpath

(PHP 5, PHP 7, PHP 8)

SimpleXMLElement::xpath對 XML 資料執行 XPath 查詢

說明

public SimpleXMLElement::xpath(字串 $expression): 陣列|null|false

xpath 方法會在 SimpleXML 節點中搜尋符合 XPath expression 的子節點。

參數

表達式

一個 XPath 路徑

返回值

成功時返回一個 陣列,包含 SimpleXMLElement 物件;若發生錯誤則返回 nullfalse

範例

範例 #1 Xpath

<?php
$string
= <<<XML
<a>
<b>
<c>text</c>
<c>stuff</c>
</b>
<d>
<c>code</c>
</d>
</a>
XML;

$xml = new SimpleXMLElement($string);

/* 搜尋 <a><b><c> */
$result = $xml->xpath('/a/b/c');

foreach (
$result as $node) {
echo
'/a/b/c: ',$node,"\n";
}

/* 相對路徑也適用... */
$result = $xml->xpath('b/c');

foreach (
$result as $node) {
echo
'b/c: ',$node,"\n";
}
?>

上述範例會輸出:

/a/b/c: text
/a/b/c: stuff
b/c: text
b/c: stuff

注意兩個結果相同。

參見

新增註解

使用者貢獻的註解 10 則註解

35
leonjanzen at gmail dot com
10 年前
要在具有命名空間的 XML 文件上執行 xpath 查詢,必須在執行查詢之前使用 SimpleXMLElement::registerXPathNamespace() 註冊命名空間。如果 XML 文件命名空間不包含前綴,則必須自行設定一個任意前綴,然後在查詢中使用它。

<?php
$strXml
= <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<mydoc xmlns="http://www.url.com/myns">
<message>Test message</message>
</mydoc>
XML;

$xmlDoc= new \SimpleXMLElement($strXml);

foreach(
$xmlDoc->getDocNamespaces() as $strPrefix => $strNamespace) {
if(
strlen($strPrefix)==0) {
$strPrefix="a"; //指定一個任意命名空間前綴。
}
$xmlDoc->registerXPathNamespace($strPrefix,$strNamespace);
}

print(
$xmlDoc->xpath("//a:message")[0]); //在查詢中使用任意命名空間前綴。
?>

這將輸出

Test message
27
grummfy at gmail dot com
14 年前
在具有命名空間的 XML 上,您需要在 xpath 請求之前執行此操作(否則將返回空陣列)

<?php
$string
= str_replace('xmlns=', 'ns=', $string); //$string 是一個包含 xml 的字串...
?>
18
drewish at katherinehouse dot com
19 年前
xpath() 也可用於根據屬性選擇元素。如需良好的 XPath 參考,請查看: http://www.w3schools.com/xpath/xpath_syntax.asp

<?php
$string
= <<<XML
<sizes>
<size label="Square" width="75" height="75" />
<size label="Thumbnail" width="100" height="62" />
<size label="Small" width="112" height="69" />
<size label="Large" width="112" height="69" />
</sizes>
XML;

$xml = simplexml_load_string($string);
$result = $xml->xpath("//size[@label='Large']");

// 顯示陣列的第一個(也是唯一)成員
echo $result[0]->asXml();
?>

腳本將顯示
<size label="Large" width="112" height="69"/>
2
Filippo Vicari
2 年前
您也可以使用條件搜尋同級元素。例如,想像一下需要此 XML 檔案中具有兩個同級標籤的所需語言的標題

<?xml version="1.0" encoding="UTF-8"?>
<IDOC BEGIN="1">
...
<PRODUCT SEGMENT="1">
<PRODUCTCODE>005</PRODUCTCODE>
<LANG>E</LANG>
<TITLE>Name</TITLE>
<LANG_ISO>EN</LANG_ISO>
</PRODUCT>
<PRODUCT SEGMENT="1">
<PRODUCTCODE>005</PRODUCTCODE>
<LANG>I</LANG>
<TITLE>Name I</TITLE>
<LANG_ISO>IT</LANG_ISO>
</PRODUCT>
...
</IDOC>

讓我們來分解一下
<?php
"//PRODUCT" // 尋找 product 標籤
"//PRODUCT/LANG[.='E']" // 在其中尋找 lang == "E"
"//PRODUCT/LANG[.='E']/../" // 向上回溯一層
"//PRODUCT/LANG[.='E']/../TITLE" // 取得 title 標籤的內容

// 結合搜尋及尋找同層標籤 ----------------------------
$xml = simplexml_load_file("fname.xml");

// 搜尋同層標籤為 "E" 的 TITLE 欄位 ----------
$title_E_array = $xml->xpath("//PRODUCT/LANG[.='E']/../TITLE"); // 預設會返回一個 SimpleXmlElement 陣列
$title = (string) $xml->xpath("//PRODUCT/LANG[.='E']/../TITLE")[0]; // 如此則只會儲存字串值
?>
11
anemik
16 年前
如果您想輕鬆地在 XML 資料中找到符合某些條件的所有記錄,例如:

....
<book id="bk101">
<author>Gambardella, Matthew</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>44.95</price>
</book>
<book id="bk102">
<author>Ralls, Kim</author>
<title>Midnight Rain</title>
<genre>Fantasy</genre>
<price>5.95</price>
</book>
...

請嘗試以下範例

<?php

$xmlStr
= file_get_contents('data/books.xml');
$xml = new SimpleXMLElement($xmlStr);
// 透過標籤值搜尋記錄:
// 尋找所有價格高於 40 美元的書籍記錄
$res = $xml->xpath("book/price[.>'40']/parent::*");
print_r($res);

?>

您將看到如下回應
陣列 (
[0] => SimpleXMLElement 物件
(
[@attributes] => 陣列
(
[id] => bk101
)

[author] => Gambardella, Matthew
[title] => XML Developer's Guide
[genre] => Computer
[price] => 44.95
[publish_date] => 2000-10-01
[description] => 深入探討使用 XML 建立應用程式

)
...
5
canuemail at gmail dot com
16 年前
如果您想根據一個值從 XML 中搜尋多個值,那麼這段程式碼可能對您有所幫助。

如果有
<Record>
<country>Pakistan</country>
<code>+92</code>
<Value>100<Value>
</Record>

那麼請嘗試這個
<?php
$sxe
= simplexml_load_file("countries.XML");
foreach(
$sxe->xpath('//RECORD') as $item) {

$row = simplexml_load_string($item->asXML());
$v = $row->xpath('//country[. ="Pakistan"]');
if(
$v[0]){
print
$item->country;
print
$item->code;
print
$item->value;
}

}
?>
3
匿名用戶
9 年前
如同先前所提,如果使用了預設命名空間 'xmlns',就像以下例子,xpath 會失敗:

<?php

$xmlstring
= $string = <<<XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
<fileVersion appName="xl" />
</workbook>
XML;
?>

xpath 無法在沒有明確指定命名空間的情況下搜尋 XML。
有兩個選項:
1. 將 'xmlns' 重新命名為其他名稱,以欺騙 xpath 認為沒有定義預設命名空間。
2. 將一個字串註冊為預設命名空間,並在所有查詢中使用該字串。很遺憾,空字串無法使用。
在 XPath2.0 成為預設函式庫之前,目前沒有其他選項。
1
awoerl at contentserv dot com
7 年前
我嘗試在我的 xpath 陳述式中使用字串函式,例如:

$oXml->xpath('substring(/foo/bar/text(), 0, 4)');

但無論我嘗試哪種語法,字串函式都無法運作。

是否有可能 xpath 方法不支援函式呼叫?
3
yetihehe at yetihehe dot com
13 年前
Xpath 實際上知道哪個元素是根元素,無論您在哪個元素上執行它。範例:

<?php

$string
= <<<XML
<a>
<b>
<c>text</c>
<c>stuff</c>
</b>
<b>
<c>code</c>
</b>
</a>
XML;

header('content-type: text/plain');

$xml = new SimpleXMLElement($string);

//相對於根元素
$b0=$xml->b[0]->xpath('//c');
while(list( ,
$node) = each($b0)) {
echo
'b[0]: //c: ',$node,"\n";
}

$b1=$xml->b[1]->xpath('//c');
while(list( ,
$node) = each($b1)) {
echo
'b[1]: //c: ',$node,"\n";
}

echo
"\n";

//相對於目前元素
$b0=$xml->b[0]->xpath('.//c');
while(list( ,
$node) = each($b0)) {
echo
'b[0]: .//c: ',$node,"\n";
}

$b1=$xml->b[1]->xpath('.//c');
while(list( ,
$node) = each($b1)) {
echo
'b[1]: .//c: ',$node,"\n";
}

?>

將會返回
b[0]: //c: text
b[0]: //c: stuff
b[0]: //c: code
b[1]: //c: text
b[1]: //c: stuff
b[1]: //c: code

b[0]: .//c: text
b[0]: .//c: stuff
b[1]: .//c: code
1
paul at pmtlogic dot com
16 年前
xpath 似乎無法處理查詢字串本身內嵌的單引號。例如,我想根據國家名稱在 XML 檔案中查找地理坐標。

XML 程式碼片段

<zones>
<zone country="Cote d'Ivoire" fullName="Yamoussoukro" geo="6.82,-5.28" id="1050"><url prefix="1001" value="fiji.html" /><url prefix="1002" value="C" /></zone>
</zones>

以下程式碼無法運作

<?php
$xml
= simplexml_load_file("my.xml");
$result = $xml->xpath("//zone[@country='Cote d\'Ivoire']");

foreach (
$result[0]->attributes() as $key => $val ) {
print
"<div class='coords'>$key: $val</div>\n";
}
?>

我嘗試了許多嵌入單引號的變體(例如,跳脫字元),但都沒有結果。W3C 也沒有提供任何說明。

此外,似乎沒有任何方法可以在屬性值中嵌入萬用字元(您可以在屬性名稱中嵌入萬用字元)。否則,以下內容在此情況下可能是一個合理的替代方案

<?php $result = $xml->xpath("//zone[@country='Cote d*Ivoire']"); ?>
To Top