PHP 的 simplexml_load_string / simplexml_load_file 提供了極其便捷的 XML 解析能力,但其返回的 SimpleXMLElement 對象行為與普通數組/對象有顯著差異。本文通過實例深度解析其特性、常見陷阱與最佳實踐。
<?php
$string = <<<EOF
<data>
<foo><bar>hello</bar></foo>
<foo><bar>world</bar></foo>
</data>
EOF;
$data = simplexml_load_string($string);
print_r($data);
print_r($data->foo);
輸出分析:
SimpleXMLElement Object
(
[foo] => Array
(
[0] => SimpleXMLElement Object ([bar] => hello)
[1] => SimpleXMLElement Object ([bar] => world)
)
)
SimpleXMLElement Object
(
[bar] => hello
)
核心發現: print_r($data->foo) 顯示為數組,但 $data->foo 直接訪問只返回第一個匹配節點!原因是 SimpleXMLElement 實現了 Traversable 接口,而非真正的數組。
<?php
// 方法一:foreach 直接遍歷(推薦)
foreach ($data->foo as $foo) {
echo $foo->bar . PHP_EOL; // hello / world
}
// 方法二:children() 遍歷所有子節點
foreach ($data->children() as $child) {
echo $child->getName() . ': ' . $child->bar . PHP_EOL;
}
// 方法三:xpath 查詢(最靈活)
$results = $data->xpath('//foo/bar');
foreach ($results as $bar) {
echo $bar . PHP_EOL;
}
處理帶屬性、命名空間、多層嵌套的字典數據:
<?xml version="1.0" encoding="UTF-8"?>
<dict num="219" id="219" name="219">
<key>你好</key>
<pos></pos>
<acceptation>Array;Array;Array;</acceptation>
<sent>
<orig>Haven't seen you for a long time. How are you?</orig>
<trans>多日不見了,你好嗎?</trans>
</sent>
<sent>
<orig>Hello! How are you?</orig>
<trans>嘿,你好?</trans>
</sent>
<!-- 更多 sent 節點 -->
</dict>
$xml = simplexml_load_string($data);
echo $xml['num']; // 219 (屬性當作數組鍵訪問)
echo $xml->attributes()->num; // 同樣效果
print_r($xml->attributes()); // 獲取所有屬性數組
<?php
$sentences = $xml->sent; // 這是一個可遍歷的 SimpleXMLElement 對象
// 正確獲取第 N 個句子
echo $xml->sent[0]->orig; // Haven't seen you...
echo $xml->sent[1]->trans; // 嘿,你好?
// 遍歷所有句子
foreach ($xml->sent as $index => $sent) {
echo "句子 $index: " . $sent->orig . " => " . $sent->trans . PHP_EOL;
}
// 轉為真正數組(需 PHP 5.4+)
$sentArray = iterator_to_array($xml->sent);
<?xml version="1.0"?>
<root xmlns:ns="https://example.com/ns">
<ns:item>值</ns:item>
</root>
<?php
$xml = simplexml_load_string($string);
$ns = $xml->getNamespaces(true);
$items = $xml->children($ns['ns']);
foreach ($items as $item) {
echo $item; // 值
}
<?php
// 錯誤:SimpleXMLElement 不能直接 json_encode
echo json_encode($xml); // 空對象 {}
// 正確:轉換為數組後再編碼
function xmlToArray($xml) {
$arr = [];
foreach ($xml as $key => $value) {
$arr[$key] = ($value instanceof SimpleXMLElement) ? xmlToArray($value) : (string)$value;
}
if ($xml->attributes()) {
$arr['@attributes'] = array_map('strval', iterator_to_array($xml->attributes()));
}
return $arr;
}
echo json_encode(xmlToArray($xml));
<?php
$xml = simplexml_load_string('123 ');
$val = $xml->num; // SimpleXMLElement 對象
echo $val + 1; // 124 (自動轉數字)
echo (string)$val; // "123" (顯式轉字符串)
echo (int)$val; // 123
echo (float)$val; // 123.0
// 比較時必須轉型
if ((string)$xml->status == 'ok') { ... }
<?php
$xml = simplexml_load_string(']]> ');
// 空節點
var_dump($xml->empty); // object(SimpleXMLElement)#2 (0) {}
// CDATA 內容
echo (string)$xml->cdata; //
xmlToArray 結果libxml_disable_entity_loader(true) 防止 XXE 攻擊iconv 轉換| 特性 | SimpleXML | DOMDocument |
|---|---|---|
| API 風格 | 屬性訪問、鏈式調用 | 標準 DOM API |
| 內存佔用 | 整樹加載 | 整樹加載 |
| XPath 支持 | 支持 | 支持 |
| 命名空間 | 基礎支持 | 完整支持 |
| 修改文檔 | 困難 | 靈活 |
| 適用場景 | 讀取為主、結構固定 | 讀寫混合、複雜操作 |
simplexml_load_string 是 PHP 解析 XML 的首選工具,核心要點只有三個:
print_r 的數組假象['attr'] 或 attributes(),內容用 (string)$node掌握這些,90% 的 XML 解析需求都能輕鬆搞定。