PHP Conference Japan 2024

simplexml_load_string

(PHP 5, PHP 7, PHP 8)

simplexml_load_string 將 XML 字串解譯為物件

說明

simplexml_load_string(
    字串 $data,
    ?字串 $class_name = SimpleXMLElement::class,
    整數 $options = 0,
    字串 $namespace_or_prefix = "",
    布林值 $is_prefix = false
): SimpleXMLElement|false

接受格式良好的 XML 字串並將其作為物件返回。

參數

data

格式良好的 XML 字串

類別名稱

您可以使用這個選用參數,以便 simplexml_load_string() 會返回指定類別的物件。該類別應繼承 SimpleXMLElement 類別。

選項

位元 ORlibxml 選項常數

命名空間或前綴

命名空間前綴或 URI。

是否為前綴

如果 namespace_or_prefix 是前綴,則為 true;如果是 URI,則為 false;預設為 false

返回值

返回一個 物件,其類別為 SimpleXMLElement,其屬性包含 XML 文件中的數據,或者在失敗時返回 false

警告

此函數可能返回布林值 false,但也可能返回一個計算結果為 false 的非布林值。請閱讀 布林值 的章節以了解更多資訊。使用 === 運算子 來測試此函數的返回值。

錯誤/例外

針對 XML 資料中找到的每個錯誤,都會產生 E_WARNING 錯誤訊息。

提示

使用 libxml_use_internal_errors() 來抑制所有 XML 錯誤,並使用 libxml_get_errors() 之後迭代它們。

範例

範例 #1 解析 XML 字串

<?php
$string
= <<<XML
<?xml version='1.0'?>
<document>
<title>四十個什麼?</title>
<from>Joe</from>
<to>Jane</to>
<body>
我知道那是答案 -- 但問題是什麼?
</body>
</document>
XML;

$xml = simplexml_load_string($string);

print_r($xml);
?>

上述範例將輸出

SimpleXMLElement Object
(
  [title] => Forty What?
  [from] => Joe
  [to] => Jane
  [body] =>
   I know that's the answer -- but what's the question?
)

此時,您可以使用 $xml->body 等等。

另請參閱

新增註記

使用者貢獻的註記 22 則註記

ascammon at hotmail dot com
13 年前
我費了好一番功夫才找到相關文件,因此將它發佈在此,希望能幫助到其他人。

如果您想使用多個 libxml 選項,請使用管道符號分隔它們,如下所示:

<?php
$xml
= simplexml_load_string($string, 'SimpleXMLElement', LIBXML_NOCDATA | LIBXML_NOBLANKS);
?>
Diego Araos, diego at klapmedia dot com
13 年前
將結果轉換為陣列的更簡單方法(需要 json 模組)。

<?php
function object2array($object) { return @json_decode(@json_encode($object),1); }
?>

範例
<?php
$xml_object
=simplexml_load_string('<SOME XML DATA');
$xml_array=object2array($xml_object);
?>
meustrus
9 年前
檢查剖析錯誤時要小心。空的 SimpleXMLElement 可能會解析為 FALSE,如果您的 XML 不包含任何文字或只包含命名空間元素,您的錯誤檢查可能是錯誤的。檢查剖析錯誤時,請務必使用 `=== FALSE`。

<?php

$xml
= <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<ns1:Root xmlns:ns1="http://example.com/custom">
<ns1:Node>這裡有一些內容</ns1:Node>
</ns1:Root>
XML;

$simplexml = simplexml_load_string($xml);

// 這會印出「剖析錯誤」。
echo ($simplexml ? '有效的 XML' : '剖析錯誤'), PHP_EOL;

// 但這會印出「這裡有一些內容」,證明
// SimpleXML 物件已成功建立。
echo $simplexml->children('http://example.com/custom')->Node, PHP_EOL;

// 請改用以下方式:
echo ($simplexml !== FALSE ? '有效的 XML' : '剖析錯誤'), PHP_EOL;

?>

參見

https://bugs.php.net/bug.php?id=31045
https://bugs.php.net/bug.php?id=30972
https://bugs.php.net/bug.php?id=69596
rowan dot collins at gmail dot com
16 年前
似乎有很多關於 SimpleXML 處理 CDATA 的「問題」的討論,以及撰寫用於移除 CDATA 的函數等等。一開始我也這麼認為,但它在 PHP 5.2.6 下的表現其實很好。

關鍵在上面範例 #6 中有提到
http://uk2.php.net/manual/en/simplexml.examples.php

「要將元素或屬性與字串比較,或將其傳遞給需要字串的函式,您必須使用 (string) 將其強制轉換為字串。否則,PHP 會將元素視為物件。」

如果標籤包含 CDATA,SimpleXML 會記住這個事實,方法是將其與元素的字串內容分開表示。因此,某些函式,包括 print_r(),可能不會顯示您預期的結果。但如果您明確地強制轉換為字串,您將獲得完整內容。

<?php
$xml
= simplexml_load_string('<foo>Text1 &amp; XML entities</foo>');
print_r($xml);
/*
SimpleXMLElement 物件
(
[0] => Text1 & XML 實體
)
*/

$xml2 = simplexml_load_string('<foo><![CDATA[Text2 & raw data]]></foo>');
print_r($xml2);
/*
SimpleXMLElement 物件
(
)
*/
// 我的 CDATA 在哪裡?

// 讓我們嘗試顯式轉換
print_r( (string)$xml );
print_r( (string)$xml2 );
/*
Text1 & XML 實體
Text2 & 原始資料
*/
// 好多了
?>
bojan
16 年前
如同前面所述,不要使用 var_dump() 或 print_r() 來查看 SimpleXML 物件結構,因為它們的回傳結果並非總是您預期的。
考慮以下情況

<?php

// xml 中的資料
$xml_txt = '
<root>
<folder ID="65" active="1" permission="1"><![CDATA[aaaa]]></folder>
<folder ID="65" active="1" permission="1"><![CDATA[bbbb]]></folder>
</root>'
;

// 將 xml 載入到 SimpleXML 物件中
$xml = simplexml_load_string($xml_txt, 'SimpleXMLElement', LIBXML_NOCDATA);//LIBXML_NOCDATA LIBXML_NOWARNING

// 查看物件結構
print_r($xml);

/* 輸出
SimpleXMLElement 物件
(
[folder] => 陣列
(
[0] => aaaa
[1] => bbbb
)

)
*/

// 但是...
foreach ($xml->folder as $value){
print_r($value);
}
/* 輸出每個 folder 元素的完整結構:
SimpleXMLElement 物件
(
[@attributes] => 陣列
(
[ID] => 65
[active] => 1
[permission] => 1
)

[0] => aaaa
)

SimpleXMLElement 物件
(
[@attributes] => 陣列
(
[ID] => 65
[active] => 1
[permission] => 1
)

[0] => bbbb
)

*/
?>
amir_abiri at ipcmedia dot com
16 年前
這似乎沒有在任何地方被記錄,但是您可以參考元素的「值」來更改它,如下所示

<?php
$xml
= simplexml_load_string('<root><number>1</number></root>');
echo
$xml->asXml(). "\n\n";

$xml->number->{0} = $xml->number->{0} + 1;

echo
$xml->asXml();
?>

會印出
<?xml version="1.0"?>
<root><number>1</number></root>

<?xml version="1.0"?>
<root><number>2</number></root>

然而,這只適用於直接賦值,不適用於其他運算符。

<?php
$xml
= simplexml_load_string('<root><number>1</number></root>');
echo
$xml->asXml(). "\n\n";

$xml->number->{0} += 1;
// 或:
$xml->number->{0}++;

echo
$xml->asXml();
?>

以上兩種情況都會導致

<?xml version="1.0"?>
<root><number>1</number></root>

<?xml version="1.0"?>
<root><number>1<0/></number></root>
nbijnens at servs dot eu
17 年前
請注意,並非所有 LIBXML 選項都支援 options 參數。

例如,LIBXML_XINCLUDE 無法使用。 但是有一個解決方法

<?php
$xml
= new DOMDocument();
$xml->loadXML ($XMLString);

$xml->xinclude();
$xml = simplexml_import_dom($xml);

?>
hattori at hanso dot com
17 年前
當序列化包含 HTML CDATA 的欄位時,以下的解決方法會出現問題。 對於 HTML 以外的任何其他內容類型,請嘗試修改 parseCDATA 函數。
序列化之前只需添加這些行。
這也是這個錯誤的解決方法 http://bugs.php.net/bug.php?id=42001

<?PHP
if(strpos($content, '<![CDATA[')) {
function
parseCDATA($data) {
return
htmlentities($data[1]);
}
$content = preg_replace_callback(
'#<!\[CDATA\[(.*)\]\]>#',
'parseCDATA',
str_replace("\n", " ", $content)
);
}
?>
mindpower
17 年前
一個簡單的擴展,添加了一個用於檢索特定屬性的方法

<?php
class simple_xml_extended extends SimpleXMLElement
{
public function
Attribute($name)
{
foreach(
$this->attributes() as $key=>$val)
{
if(
$key == $name)
return (string)
$val;
}
}

}

$xml = simplexml_load_string('
<xml>
<dog type="poodle" owner="Mrs Smith">Rover</dog>
</xml>'
, 'simple_xml_extended');

echo
$xml->dog->Attribute('type');

?>

輸出 'poodle'

我比較喜歡用這種技巧,而不是將屬性進行類型轉換。
javalc6 at gmail dot com
16 年前
我想要將一個包含字串和其他相同類型陣列的陣列轉換成一個 simplexml 物件。

以下是我開發用於執行此轉換的函式 array2xml 的程式碼。請注意,這段程式碼很簡單,沒有任何檢查。

<?php
函數 array2xml($array, $tag) {

函數
ia2xml($array) {
$xml="";
foreach (
$array as $key=>$value) {
if (
is_array($value)) {
$xml.="<$key>".ia2xml($value)."</$key>";
} else {
$xml.="<$key>".$value."</$key>";
}
}
return
$xml;
}

return
simplexml_load_string("<$tag>".ia2xml($array)."</$tag>");
}

$test['type']='lunch';
$test['time']='12:30';
$test['menu']=array('entree'=>'salad', 'maincourse'=>'steak');

echo
array2xml($test,"meal")->asXML();
?>
Bob
15 年前
這是我的簡易 SimpleXML 包裝函式。
據我所知,它的功能和 Julio Cesar Oliveira 的(上面)一樣。
它會將 XML 字串解析為多維關聯陣列。
第二個參數是一個回呼函式,會對所有資料執行(例如,如果您想要修剪所有資料,就像 Julio 在他的函式中所做的那樣,只需將 'trim' 作為第二個參數傳遞即可)。
<?php
function unserialize_xml($input, $callback = null, $recurse = false)
/* bool/array unserialize_xml ( string $input [ , callback $callback ] )
* 將 XML 字串反序列化為多維關聯陣列,可選用回呼函式處理所有非陣列資料
* 失敗時返回 false
* 注意:
* 根 XML 標籤將被移除
* 由於其遞迴特性,unserialize_xml() 也支援 SimpleXMLElement 物件和陣列作為輸入
* 使用 simplexml_load_string() 進行 XML 解析,詳情請參閱 SimpleXML 文件
*/
{
// 取得輸入,如果是遞迴的頂層,則使用 simplexml 載入 xml 字串
$data = ((!$recurse) && is_string($input))? simplexml_load_string($input): $input;
// 將 SimpleXMLElements 轉換為陣列
if ($data instanceof SimpleXMLElement) $data = (array) $data;
// 遞迴處理陣列
if (is_array($data)) foreach ($data as &$item) $item = unserialize_xml($item, $callback, true);
// 執行回呼函式並返回
return (!is_array($data) && is_callable($callback))? call_user_func($callback, $data): $data;
}
?>
AllenJB
12 年前
<?php
$xml
= json_decode(json_encode((array) simplexml_load_string($string)), 1);
?>

提醒您,json_encode 會嘗試將資料轉換為 UTF-8,但它並不知道來源編碼。如果您沒有使用 UTF-8,此方法可能會導致編碼問題。
Julio Cesar Oliveira
15 年前
XML2Array 函式現在支援遞迴!

<?php
function XML2Array( $xml, $recursive = false )
{
if ( !
$recursive )
{
$array = simplexml_load_string( $xml ) ;
}
else
{
$array = $xml ;
}

$newArray = array() ;
$array = (array) $array ;
foreach (
$array as $key => $value )
{
$value = (array) $value ;
if ( isset(
$value [ 0 ] ) )
{
$newArray [ $key ] = trim( $value [ 0 ] ) ;
}
else
{
$newArray [ $key ] = XML2Array( $value , true ) ;
}
}
return
$newArray ;
}
?>
artistan at gmail dot com
9 年前
這是針對 Bob 的簡易 SimpleXML 包裝函式的更新版本。
我注意到他的版本會將空的 SimpleXMLElement 轉換成空的陣列。

<?php
/**
* https://php.dev.org.tw/manual/en/function.simplexml-load-string.php#91564
*
* bool/array unserialize_xml ( string $input [ , callback $callback ] )
* 將 XML 字串反序列化為多維關聯陣列,可選用回呼函式處理所有非陣列資料
* 失敗時回傳 false
* 注意:
* 根 XML 標籤會被移除
* 由於其遞迴特性,unserialize_xml() 也支援 SimpleXMLElement 物件和陣列作為輸入
* 使用 simplexml_load_string() 進行 XML 解析,詳情請見 SimpleXML 文件
*
* @param $input
* @param null $callback
* @param bool $recurse
* @return array|mixed
*
*/
function unserialize_xml($input, $callback = null, $recurse = false)
{
// 取得輸入,如果是遞迴的頂層,則使用 simplexml 載入 xml 字串
$data = ((!$recurse) && is_string($input))? simplexml_load_string($input): $input;
// 將 SimpleXMLElements 轉換為陣列
if ($data instanceof SimpleXMLElement){
if(!empty(
$data)){
$data = (array) $data;
} else {
$data = '';
}
}
// 遞迴處理陣列
if (is_array($data)) foreach ($data as &$item) $item = unserialize_xml($item, $callback, true);
// 執行回呼函式並回傳
return (!is_array($data) && is_callable($callback))? call_user_func($callback, $data): $data;
}
?>
匿名
12 年前
使用 libxml_disable_entity_loader() 來限制外部檔案的載入。參考 http://www.idontplaydarts.com/2011/02/scanning-the-internal-network-using-simplexml/
jeff at creabilis dot com
15 年前
如果要設定輸出 XML 的字元集,只需像這樣設定 encoding 屬性:

<?php simplexml_load_string('<?xml version="1.0" encoding="utf-8"?><xml/>'); ?>

$xml->asXML 輸出的 XML 將包含像 'é' 這樣的重音字元,而不是 &#xE9;。

希望這個有幫助
m dot ament at mailcity dot com
17 年前
警告

XML 資料的解析會在遇到字元 0 時停止。
請避免在您的 XML 資料中使用這個字元。
cellog at php dot net
20 年前
simplexml 無法簡單地使用 foreach 迴圈處理 CDATA 區段。

<?php
$sx
= simplexml_load_string('
<test>
<one>hi</one>
<two><![CDATA[stuff]]></two>
<t>
<for>two</for>
</t>
<multi>one</multi>
<multi>two</multi>
</test>'
);
foreach((array)
$sx as $tagname => $val) {
if (
is_string($val)) {
// <one> 會在這裡
} elseif (is_array($val)) {
// <multi> 會在這裡,因為它出現多次
} elseif (is_object($val)) {
// <t> 會在這裡,因為它包含標籤
// <two> 會在這裡,因為它包含 CDATA!
}
}
?>

要在迴圈中測試,請執行以下操作

<?php
if (count((array) $val) == 0) {
// 這不是包含其他標籤的標籤
$val = '' . $val;
// 現在 CDATA 神奇地顯示出來了。
}
?>
Pedro
17 年前
注意

simplexml_load_string 對於 (&lt;, &gt;, &amp;, &quot; 和 &apos;) 以外的實體會有問題。

請改用數值字元參考!
Maciek Ruckgaber <maciekrb at gmai dot com>
19 年前
在疑惑了一段時間後,我才意識到一些事情(也許很明顯,但對我來說並非如此)。希望可以幫助其他人不要像我一樣浪費時間 :-P

當您有類似以下的內容時

<?php
$xmlstr
= <<<XML
<?xml version="1.0" encoding="utf-8"?>
<double xmlns="http://foosite.foo/">2328</double>
XML;
?>

您的 simpleXML 物件會被「轉換」成 text() 內容

<?php
$xml
= simplexml_load_string($xmlstr);
echo
$xml; // 這會輸出 2328 (字串)
?>
erguven dot m at gmail dot com
7 年前
如果您想使用命名空間中存在的類別,請使用它的完整名稱。 simple_load_string 無法辨識簡短名稱。

class.new.php
<?php
namespace foo\bar;

class new extends
SimpleXMLElement
{
public function do()
{
echo
"done";
}
}
?>

false.php
<?php
use \foo\bar\new;

$result = simplexml_load_string($xml, 'new'); // 這會產生警告
$result->do(); // 致命錯誤
?>

true.php
<?php
use \foo\bar\new;
$result = simplexml_load_string($xml, '\foo\bar\new');

$result->do(); // 輸出 done
?>
To Top