最常用、可靠的方式是用递归函数手动遍历并构建数组,能准确区分属性、文本、子节点并处理重复标签;而json_decode(json_encode((array)$xml), true)易丢失属性、覆盖同名节点,仅适用于无属性无重复的简单场景。
PHP 将 XML 对象(SimpleXMLElement)转成数组,最常用、可靠的方式是用递归函数手动遍历并构建数组。因为 json_decode(json_encode((array)$xml), true) 这种“伪转换”在属性、文本混合、重复子节点、CDATA 等场景下容易出错或丢失数据。
这个方法能准确区分元素属性、文本内容、子节点,并保留结构层次:
function xmlToArray($xml) {
if (!($xml instanceof SimpleXMLElement)) {
return $xml;
}
$array = [];
// 处理属性
$attributes = $xml->attributes();
if ($attributes && count($attributes) > 0) {
foreach ($attributes as $attr => $value) {
$array['@attributes'][$attr] = (string)$value;
}
}
// 处理子节点(含文本节点)
$children = $xml->children();
if (count($children) > 0) {
foreach ($children as $childName => $child) {
$childArray = xmlToArray($child);
if (!isset($array[$childName])) {
$array[$childName] = $childArray;
} else {
// 同名子节点多个时转为数组(避免覆盖)
if (!is_array($array[$childName]) || !isset($array[$childName][0])) {
$array[$childName] = [$array[$childName]];
}
$array[$childName][] = $childArray;
}
}
} else {
// 只有文本内容(无子节点)
$text = trim((string)$xml);
if ($text !== '' || isset($array['@attributes'])) {
$array['#text'] = $text;
}
}
return $array;
}
// 使用示例
$xmlStr = '张三 - a
- b
';
$xml = simplexml_load_string($xmlStr);
$result = xmlToArray($xml);
print_r($result);
如果 XML 结构非常规整(比如全是单层子节点、无属性、无同名多节点),可用更简方式:
$arr = json_decode(json_encode($xml), true);
(array)$xml 强转,会丢失结构信息 会覆盖第一个,需靠 @attributes 和 #text 区分逻辑simplexml_load_string($xml, null, LIBXML_NOBLANKS, 'ns') 并在递归中调用 $xml->children('ns', true)
基本上就这些。核心是别图省事用 json 中转,写个十几行递归函数反而更稳、更可控。