首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP SimpleXML 解析 XML 完全指南:從入門到避坑

     編輯:PHP 相關知識

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 結構解析實戰

處理帶屬性、命名空間、多層嵌套的字典數據:

<?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;  // 值
}

常見陷阱與解決方案

1. 對象無法直接序列化

<?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));

2. 類型轉換陷阱

<?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') { ... }

3. 空節點與 CDATA

<?php
$xml = simplexml_load_string(']]>');

// 空節點
var_dump($xml->empty);  // object(SimpleXMLElement)#2 (0) {}

// CDATA 內容
echo (string)$xml->cdata;  // 

性能優化建議

  • 大文件用 XMLReader:流式解析,內存常數級,適合超大 XML
  • 緩存解析結果:相同 XML 多次解析時,緩存 xmlToArray 結果
  • 禁用實體加載:libxml_disable_entity_loader(true) 防止 XXE 攻擊
  • 編碼預處理:確保輸入為 UTF-8,非 UTF-8 先 iconv 轉換

對比:SimpleXML vs DOMDocument

特性SimpleXMLDOMDocument
API 風格屬性訪問、鏈式調用標準 DOM API
內存佔用整樹加載整樹加載
XPath 支持支持支持
命名空間基礎支持完整支持
修改文檔困難靈活
適用場景讀取為主、結構固定讀寫混合、複雜操作

總結

simplexml_load_string 是 PHP 解析 XML 的首選工具,核心要點只有三個:

  1. 同名節點用 foreach / 索引訪問,別信 print_r 的數組假象
  2. 屬性用 ['attr'] 或 attributes(),內容用 (string)$node
  3. 需修改文檔或處理複雜命名空間時,改用 DOMDocument

掌握這些,90% 的 XML 解析需求都能輕鬆搞定。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved