PHP Conference Japan 2024

基本 SimpleXML 用法

本參考中的許多範例都需要 XML 字串。為了避免在每個範例中重複此字串,我們將其放入一個檔案中,並在每個範例中包含此檔案。此包含的檔案顯示在以下範例章節中。或者,您可以建立 XML 文件,並使用 simplexml_load_file() 讀取它。

範例 #1 包含帶有 XML 字串的 example.php 檔案

<?php
$xmlstr
= <<<XML
<?xml version='1.0' standalone='yes'?>
<movies>
<movie>
<title>PHP:剖析器背後的故事</title>
<characters>
<character>
<name>程式設計師小姐</name>
<actor>Onlivia Actora</actor>
</character>
<character>
<name>程式設計師先生</name>
<actor>El Act&#211;r</actor>
</character>
</characters>
<plot>
所以,這個語言。它就像是一個程式語言。還是它是一個
腳本語言?在這部驚悚的紀錄片惡搞中,一切都將揭曉。
</plot>
<great-lines>
<line>PHP 解決了我所有的網頁問題</line>
</great-lines>
<rating type="thumbs">7</rating>
<rating type="stars">5</rating>
</movie>
</movies>
XML;
?>

當從基本的 XML 文件中提取字串或數字時,SimpleXML 的簡單性最為明顯。

範例 #2 取得 <plot>

<?php
include 'example.php';

$movies = new SimpleXMLElement($xmlstr);

echo
$movies->movie[0]->plot;
?>

上面的範例將輸出

   So, this language. It's like, a programming language. Or is it a
   scripting language? All is revealed in this thrilling horror spoof
   of a documentary.

若 XML 文件中的元素包含 PHP 命名慣例下不允許的字元(例如連字號),則可以使用大括號和單引號將元素名稱括起來來存取。

範例 #3 取得 <line>

<?php
include 'example.php';

$movies = new SimpleXMLElement($xmlstr);

echo
$movies->movie->{'great-lines'}->line;
?>

上面的範例將輸出

PHP solves all my web problems

範例 #4 在 SimpleXML 中存取非唯一元素

當一個元素的 multiple 實例作為單個父元素的子元素存在時,則適用正常的迭代技術。

<?php
include 'example.php';

$movies = new SimpleXMLElement($xmlstr);

/* 對於每個 <character> 節點,我們都 echo 一個單獨的 <name>。*/
foreach ($movies->movie->characters->character as $character) {
echo
$character->name, ' 由 ', $character->actor, PHP_EOL;
}

?>

上面的範例將輸出

Ms. Coder played by Onlivia Actora
Mr. Coder played by El ActÓr

注意:

屬性(先前範例中的 $movies->movie)不是陣列。它們是可以迭代存取的物件。

範例 #5 使用屬性

到目前為止,我們僅涵蓋了讀取元素名稱及其值的工作。SimpleXML 也可以存取元素屬性。就像存取 陣列 的元素一樣,存取元素的屬性。

<?php
include 'example.php';

$movies = new SimpleXMLElement($xmlstr);

/* 存取第一部電影的 <rating> 節點。
* 也輸出評級量表。*/
foreach ($movies->movie[0]->rating as $rating) {
switch((string)
$rating['type']) { // 將屬性作為元素索引取得
case 'thumbs':
echo
$rating, ' 豎起大拇指';
break;
case
'stars':
echo
$rating, ' 星星';
break;
}
}
?>

上面的範例將輸出

7 thumbs up5 stars

範例 #6 比較元素和帶有文字的屬性

若要將元素或屬性與字串進行比較,或將其傳遞到需要字串的函式中,則必須使用 (string) 將其轉換為字串。否則,PHP 會將元素視為物件。

<?php
include 'example.php';

$movies = new SimpleXMLElement($xmlstr);

if ((string)
$movies->movie->title == 'PHP:剖析器背後的故事') {
print
'我最喜歡的電影。';
}

echo
htmlentities((string) $movies->movie->title);
?>

上面的範例將輸出

My favorite movie.PHP: Behind the Parser

範例 #7 比較兩個元素

即使兩個 SimpleXMLElement 指向同一個元素,它們也被認為是不同的。

<?php
include 'example.php';

$movies1 = new SimpleXMLElement($xmlstr);
$movies2 = new SimpleXMLElement($xmlstr);
var_dump($movies1 == $movies2);
?>

上面的範例將輸出

bool(false)

範例 #8 使用 XPath

SimpleXML 內建支援 XPath。要尋找所有 <character> 元素

<?php
include 'example.php';

$movies = new SimpleXMLElement($xmlstr);

foreach (
$movies->xpath('//character') as $character) {
echo
$character->name, ' played by ', $character->actor, PHP_EOL;
}
?>

'//' 作為萬用字元。若要指定絕對路徑,請省略其中一個斜線。

上面的範例將輸出

Ms. Coder played by Onlivia Actora
Mr. Coder played by El ActÓr

範例 #9 設定值

SimpleXML 中的資料不必是常數。該物件允許操作其所有元素。

<?php
include 'example.php';
$movies = new SimpleXMLElement($xmlstr);

$movies->movie[0]->characters->character[0]->name = 'Miss Coder';

echo
$movies->asXML();
?>

上面的範例將輸出

<?xml version="1.0" standalone="yes"?>
<movies>
 <movie>
  <title>PHP: Behind the Parser</title>
  <characters>
   <character>
    <name>Miss Coder</name>
    <actor>Onlivia Actora</actor>
   </character>
   <character>
    <name>Mr. Coder</name>
    <actor>El Act&#xD3;r</actor>
   </character>
  </characters>
  <plot>
   So, this language. It's like, a programming language. Or is it a
   scripting language? All is revealed in this thrilling horror spoof
   of a documentary.
  </plot>
  <great-lines>
   <line>PHP solves all my web problems</line>
  </great-lines>
  <rating type="thumbs">7</rating>
  <rating type="stars">5</rating>
 </movie>
</movies>

範例 #10 新增元素和屬性

SimpleXML 具有輕鬆新增子元素和屬性的能力。

<?php
include 'example.php';
$movies = new SimpleXMLElement($xmlstr);

$character = $movies->movie[0]->characters->addChild('character');
$character->addChild('name', 'Mr. Parser');
$character->addChild('actor', 'John Doe');

$rating = $movies->movie[0]->addChild('rating', 'PG');
$rating->addAttribute('type', 'mpaa');

echo
$movies->asXML();
?>

上面的範例將輸出

<?xml version="1.0" standalone="yes"?>
<movies>
 <movie>
  <title>PHP: Behind the Parser</title>
  <characters>
   <character>
    <name>Ms. Coder</name>
    <actor>Onlivia Actora</actor>
   </character>
   <character>
    <name>Mr. Coder</name>
    <actor>El Act&#xD3;r</actor>
   </character>
  <character><name>Mr. Parser</name><actor>John Doe</actor></character></characters>
  <plot>
   So, this language. It's like, a programming language. Or is it a
   scripting language? All is revealed in this thrilling horror spoof
   of a documentary.
  </plot>
  <great-lines>
   <line>PHP solves all my web problems</line>
  </great-lines>
  <rating type="thumbs">7</rating>
  <rating type="stars">5</rating>
 <rating type="mpaa">PG</rating></movie>
</movies>

範例 #11 DOM 互通性

PHP 提供一種機制,可以在 SimpleXML 和 DOM 格式之間轉換 XML 節點。此範例顯示如何將 DOM 元素變更為 SimpleXML。

<?php
$dom
= new DOMDocument;
$dom->loadXML('<books><book><title>blah</title></book></books>');
if (!
$dom) {
echo
'Error while parsing the document';
exit;
}

$books = simplexml_import_dom($dom);

echo
$books->book[0]->title;
?>

上面的範例將輸出

blah

新增筆記

使用者貢獻的筆記 9 則筆記

85
rowan dot collins at gmail dot com
9 年前
有一個常見的「技巧」,通常建議將 SimpleXML 物件轉換為陣列,方法是透過 json_encode() 執行它,然後再使用 json_decode()。我想解釋為什麼這是一個壞主意。

最簡單來說,因為 SimpleXML 的重點是比純陣列更容易使用且更強大。例如,您可以寫 <?php $foo->bar->baz['bing'] ?>,它的意義與 <?php $foo->bar[0]->baz[0]['bing'] ?> 相同,無論 XML 中有多少個 bar 或 baz 元素;如果您寫 <?php (string)$foo->bar[0]->baz[0] ?>,您會取得該節點的所有字串內容(包括 CDATA 區段),無論它是否有子元素或屬性。您還可以存取命名空間資訊、對 XML 進行簡單編輯的能力,甚至可以「匯入」到 DOM 物件中,以進行更強大的操作。將物件轉換為陣列而不是閱讀理解此頁面上的範例,將會失去所有這些功能。

此外,由於它並非設計用於此目的,因此轉換為 JSON 並轉換回實際上會在某些情況下遺失資訊。例如,命名空間中的任何元素或屬性都會被直接捨棄,如果元素也有子元素或屬性,則會捨棄任何文字內容。有時候,這並不重要,但是如果您習慣將所有內容都轉換為陣列,最終還是會遇到麻煩。

當然,您可以編寫更聰明的轉換,而不會有這些限制,但是到了那時候,您根本無法從 SimpleXML 中獲得任何價值,應該只使用較低階的 XML Parser 函式或 XMLReader 類別來建立結構。您仍然不會擁有 SimpleXML 的額外便利功能,但那是您的損失。
66
jishcem at gmail dot com
11 年前
對我來說,使用陣列比使用物件更容易,

所以我使用了這段程式碼,

$xml = simplexml_load_file('xml_file.xml');

$json_string = json_encode($xml);

$result_array = json_decode($json_string, TRUE);

希望這對某人有幫助
9
Anonymous
7 年前
如果您的 xml 字串包含以「0」和「1」編碼的布林值,當您直接將元素轉換為布林值時,會遇到問題

$xmlstr = <<<XML
<?xml version='1.0' standalone='yes'?>
<values>
<truevalue>1</truevalue>
<falsevalue>0</falsevalue>
</values>
XML;
$values = new SimpleXMLElement($xmlstr);
$truevalue = (bool)$values->truevalue; // true
$falsevalue = (bool)$values->falsevalue; // 也會是 true !!!

相反地,您需要先轉換為字串或整數

$truevalue = (bool)(int)$values->truevalue; // true
$falsevalue = (bool)(int)$values->falsevalue; // false
2
Josef
3 年前
如何找出節點是否存在

<?xml version='1.0' standalone='yes'?>
<book>
<author>Josef</author>
<isbn></isbn>
</book>

empty($xml->isbn) 會是 true
isset($xml->isbn) 會是 true

empty($xml->title) 會是 true
isset($xml->title) 會是 false
17
ie dot raymond at gmail dot com
14 年前
如果你的回應需要輸出有效的 XML,別忘了除了輸出 asXML() 的結果外,還要設定你的標頭內容類型為 XML。

<?php

$xml
=simplexml_load_file('...');
...
...
xml 相關操作
...

//在你的回應中輸出 xml:
header('Content-Type: text/xml');
echo
$xml->asXML();
?>
10
gkokmdam at zonnet dot nl
13 年前
關於 xpath 查詢和預設命名空間的小提示。SimpleXML 背後的 XML 系統看起來與我認為 .NET 使用的 XML 系統有相同的運作方式:當需要存取預設命名空間中的內容時,必須使用 registerXPathNamespace 宣告命名空間,然後使用其前綴來存取原本存在於預設命名空間中的元素。

<?php
$string
= <<<XML
<?xml version='1.0'?>
<document xmlns="http://www.w3.org/2005/Atom">
<title>四十什麼?</title>
<from>喬</from>
<to>珍</to>
<body>
我知道答案是那個 -- 但問題是什麼?
</body>
</document>
XML;

$xml = simplexml_load_string($string);
$xml->registerXPathNamespace("def", "http://www.w3.org/2005/Atom");

$nodes = $xml->xpath("//def:document/def:title");

?>
8
kdos
13 年前
使用類似 `is_object($xml->module->admin)` 的方式來檢查是否真的存在名為 "admin" 的節點,似乎不如預期,因為即使特定節點不存在,simplexml 也總是會回傳一個物件 - 在這種情況下是一個空的物件。
對我來說,在這種情況下,使用傳統的 empty() 函式似乎可以正常運作。

乾杯
5
Max K.
14 年前
出自 README 檔案

SimpleXML 旨在提供一種簡單的方式來存取 XML 資料。

SimpleXML 物件遵循四個基本規則

1) 屬性表示元素迭代器
2) 數值索引表示元素
3) 非數值索引表示屬性
4) 字串轉換允許存取 TEXT 資料

當迭代屬性時,擴展總是會迭代所有具有該元素名稱的節點。
因此,必須呼叫 method children() 來迭代子節點。 但執行以下操作
但以下操作也是可以的
foreach ($obj->node_name as $elem) {
// 對 $elem 進行某些操作
}
總是會產生 'node_name' 元素的迭代。 因此,不需要進一步檢查來區分該類型節點的數量。
因此不需要額外檢查該類型節點的數量

當通過屬性存取元素的 TEXT 資料時,結果不包含子元素的 TEXT 資料。
當透過屬性存取元素中的文字資料時,結果不包含子元素的文字資料。

已知問題
============

由於引擎問題,目前無法透過索引 0 存取子元素:$object->property[0]。
目前由於引擎問題,無法以索引值 0 存取子元素,例如:$object->property[0]。
-1
php at keith tyler dot com
14 年前
[編輯註:但是 SimpleXMLIterator 類別確實實作了這些方法。]

儘管 SimpleXMLElement 聲稱是可迭代的,但它似乎沒有正確實作標準的 Iterator 介面函式,例如 ::next 和 ::reset。 因此,雖然 foreach() 可以運作,但像 next()、current() 或 each() 這樣的函式似乎不如預期的那樣運作 -- 指標似乎永遠不會移動或持續被重設。
To Top