XML 仍是系統整合、配置檔、API 回應常用格式。本文封裝 XMLParser 類別,基於 PHP 內建 SimpleXML 擴展,提供檔案與字串兩種來源載入,自動轉換為關聯陣列,並包含格式驗證與錯誤處理。
loadXmlFile($file):從檔案路徑載入 XML 並轉陣列。loadXmlString($string):從字串載入 XML 並轉陣列。xml_parser_create 格式驗證,避免 SimpleXML 載入失敗拋出警告。<?php
class XMLParser {
public function loadXmlFile($xmlfile) {
$xmlstring = file_exists($xmlfile) ? file_get_contents($xmlfile) : '';
list($flag, $data) = $this->parser($xmlstring);
return $this->response($flag, $data);
}
public function loadXmlString($xmlstring) {
list($flag, $data) = $this->parser($xmlstring);
return $this->response($flag, $data);
}
private function parser($xmlstring) {
$flag = false;
$data = [];
if ($this->checkXmlFormat($xmlstring)) {
$flag = true;
// SimpleXML 載入,LIBXML_NOCDATA 將 CDATA 節點當作文字節點處理
$data = simplexml_load_string($xmlstring, 'SimpleXMLElement', LIBXML_NOCDATA);
$this->objectToArray($data);
}
return [$flag, $data];
}
private function checkXmlFormat($xmlstring) {
if ($xmlstring === '') return false;
$parser = xml_parser_create();
$result = xml_parse_into_struct($parser, $xmlstring, $vals, $indexs);
xml_parser_free($parser);
return $result === 1; // 1=成功, 0=失敗
}
private function objectToArray(&$object) {
$object = (array)$object;
foreach ($object as $key => &$value) {
if ($value === '') {
$value = '';
} elseif (is_object($value) || is_array($value)) {
$this->objectToArray($value);
$object[$key] = $value;
}
}
}
private function response($flag = false, $data = []) {
return [$flag, $data];
}
}
?>
<?php
require 'XMLParser.class.php';
$xmlfile = 'file.xml';
$xmlstring = '
1000
100
fdipzone
1
28
';
$parser = new XMLParser();
echo "=== 載入檔案 ===\n";
list($flag, $data) = $parser->loadXmlFile($xmlfile);
if ($flag) print_r($data);
echo "\n=== 載入字串 ===\n";
list($flag, $data) = $parser->loadXmlString($xmlstring);
if ($flag) print_r($data);
Array
(
[status] => 1000
[info] =>
[result] => Array
(
[id] => 100
[name] => fdipzone
[gender] => 1
[age] => 28
)
)
若 XML 含多個同名子節點:
- Apple
- Banana
SimpleXML 會轉為陣列,但需注意:simplexml_load_string 回傳的物件屬性存取 `$xml->item` 僅取第一個,需用 `$xml->item[0]`、`$xml->item[1]` 或 `foreach` 遍歷。轉陣列後自動變為數值索引陣列。
PHP Guide
屬性需透過 `$xml->book['id']` 存取,轉陣列時會併入 `@attributes` 鍵(視 PHP 版本而定),建議手動處理屬性提取。
...
SimpleXML 需註冊命名空間:$xml->registerXPathNamespace('ns', 'https://example.com'),再用 XPath 查詢。
SimpleXML 將整份文件載入記憶體,>50MB 可能導致記憶體耗盡。大檔案建議使用 XMLReader (Pull Parser) 流式解析。
private function checkXmlFormat($xmlstring) {
if ($xmlstring === '') return false;
libxml_use_internal_errors(true);
$parser = xml_parser_create();
$result = xml_parse_into_struct($parser, $xmlstring, $vals, $indexs);
xml_parser_free($parser);
if ($result !== 1) {
$errors = libxml_get_errors();
libxml_clear_errors();
error_log('XML 格式錯誤: ' . print_r($errors, true));
}
return $result === 1;
}
| 方案 | 特性 | 適用場景 |
|---|---|---|
| SimpleXML (本類別) | 簡單、記憶體載入、自動物件/陣列轉換 | 中小型 XML、配置檔、API 回應 |
| DOMDocument | 完整 DOM 樹、XPath、命名空間支援佳 | 複雜 XML 操作、需修改寫回 |
| XMLReader | 流式、低記憶體、單向讀取 | 大型 XML 匯入、日誌分析 |
| XMLParser (SAX) | 事件驅動、低記憶體、回調複雜 | 高效能串流處理 |