PHP 使用正則表達式解析 XML:輕量級節點擷取技巧
適用場景與限制
正則解析 XML 適合:
- 結構固定、簡單的 XML 片段
- 不想引入 DOM/SimpleXML 擴充的輕量環境
- 一次性腳本、快速原型
⚠️ 警告: 複雜 XML(巢狀深度、屬性、命名空間、CDATA、實體編碼)嚴禁用正則解析,請改用 SimpleXML、DOMDocument 或 XMLReader。
範例 XML 資料
<?xml version="1.0" encoding="UTF-8"?>
<humans>
<zhangying>
<name>張映</name>
<sex>男</sex>
<old>28</old>
</zhangying>
<tank>
<name>tank</name>
<sex>男</sex>
<old>28</old>
</tank>
</humans>
正則解析實作
<?php
// 1. 讀取 XML 內容
$xml = '';
$f = fopen('person.xml', 'r');
while ($data = fread($f, 4096)) {
$xml .= $data;
}
fclose($f);
// 2. 擷取最外層 內容
// /s 修飾符讓 . 匹配換行符
preg_match_all('/(.*?)<\/humans>/s', $xml, $humansMatches);
// 3. 遍歷每個人節點
foreach ($humansMatches[1] as $personXml) {
// 擷取子節點
preg_match_all('/(.*?)<\/name>/', $personXml, $nameMatches);
preg_match_all('/(.*?)<\/sex>/', $personXml, $sexMatches);
preg_match_all('/(.*?)<\/old>/', $personXml, $oldMatches);
// 整合輸出
foreach ($nameMatches[1] as $idx => $name) {
$sex = $sexMatches[1][$idx] ?? '';
$old = $oldMatches[1][$idx] ?? '';
echo "{$name} - {$sex} - {$old}<br>";
}
}
/* 輸出:
張映 - 男 - 28
tank - 男 - 28
*/
?>
正則模式解析
| 模式 | 說明 |
/(.*?)<\/humans>/s | 貪婪匹配 內容,.*? 非貪婪,/s 跨行 |
/(.*?)<\/name>/ | 擷取 name 節點文字內容 |
(.*?) | 捕獲組,非貪婪匹配任意字符(含換行需 /s) |
進階:統一解析函式
<?php
function parseXmlNodes($xml, $parentTag, $childTags) {
$results = [];
$parentPattern = "/<$parentTag>(.*?)<\/$parentTag>/s";
if (!preg_match_all($parentPattern, $xml, $parentMatches)) {
return $results;
}
foreach ($parentMatches[1] as $nodeXml) {
$item = [];
foreach ($childTags as $tag) {
$pattern = "/<$tag>(.*?)<\/$tag>/s";
preg_match($pattern, $nodeXml, $match);
$item[$tag] = $match[1] ?? null;
}
$results[] = $item;
}
return $results;
}
// 使用
$data = parseXmlNodes($xml, 'humans', ['name', 'sex', 'old']);
print_r($data);
/*
Array
(
[0] => Array ( [name]=>張映 [sex]=>男 [old]=>28 )
[1] => Array ( [name]=>tank [sex]=>男 [old]=>28 )
)
*/
?>
標準庫替代方案對比
| 方法 | 優點 | 缺點 | 推薦場景 |
| 正則 preg_match | 無依賴、極快、記憶體小 | 脆弱、不支援巢狀/屬性/命名空間 | 固定格式、簡單片段、一次性腳本 |
| SimpleXML | 語法直覺、物件導向、XPath 支援 | 大檔案記憶體壓力大 | 中小型 XML、配置檔、API 回應 |
| DOMDocument | 完整 DOM 模型、XPath、命名空間 | API 冗長、記憶體佔用高 | 複雜 XML、需修改/驗證、XSLT 轉換 |
| XMLReader | 流式解析、常數記憶體、高效能 | 單向游標、API 較底層 | 大型 XML(>100MB)、串流處理 |
SimpleXML 同功能實作(推薦生產環境)
<?php
$xml = simplexml_load_file('person.xml');
foreach ($xml->children() as $person) {
echo "{$person->name} - {$person->sex} - {$person->old}<br>";
}
?>