You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将XML字符串转换为不同结构的PHP数组?多同类型子节点处理遇阻

解决XML转PHP数组时多同类型子节点的问题

我太懂这种头疼的情况了——当XML里存在多个同名字节点时,普通的DOM解析逻辑很容易把它们覆盖成单个值,完全不是我们想要的数组结构。我来帮你重构这个parseXml方法,让它能正确处理多子节点的场景。

问题根源

你的原有方法大概率是直接将每个子节点的键值对赋值到数组中,类似这样:

$array[$node->nodeName] = $this->parseXml($node->C14N());

这种写法在遇到重复节点时,后面的节点会直接覆盖前面的,导致最终数组里只剩最后一个节点的值。

修改后的完整方法

/**
 * 将XML字符串转换为数组,支持处理多个同类型子节点
 *
 * @param string $xmlString XML字符串
 * @return array
 */
private function parseXml($xmlString) {
    $doc = new DOMDocument;
    // 禁用错误提示,避免XML格式不规范时抛出警告
    $doc->loadXML($xmlString, LIBXML_NOERROR | LIBXML_NOWARNING);
    $root = $doc->documentElement;
    
    return $this->convertNodeToArray($root);
}

/**
 * 递归将DOM节点转换为数组,核心处理多同节点逻辑
 *
 * @param DOMNode $node
 * @return mixed
 */
private function convertNodeToArray(DOMNode $node) {
    $result = [];
    
    // 处理文本节点(如果是纯文本内容)
    if ($node->nodeType === XML_TEXT_NODE) {
        $value = trim($node->nodeValue);
        return $value === '' ? null : $value;
    }
    
    // 处理属性
    if ($node->hasAttributes()) {
        foreach ($node->attributes as $attr) {
            $result['@' . $attr->name] = $attr->value;
        }
    }
    
    // 处理子节点
    if ($node->hasChildNodes()) {
        foreach ($node->childNodes as $child) {
            $childValue = $this->convertNodeToArray($child);
            
            if ($childValue === null) {
                continue;
            }
            
            $childName = $child->nodeName;
            
            // 关键逻辑:如果该键已存在,转成数组
            if (isset($result[$childName])) {
                // 如果当前不是数组,先把现有值转成数组
                if (!is_array($result[$childName])) {
                    $result[$childName] = [$result[$childName]];
                }
                // 添加新的子节点值
                $result[$childName][] = $childValue;
            } else {
                // 第一次出现,直接赋值
                $result[$childName] = $childValue;
            }
        }
    }
    
    // 如果结果只有一个子节点且没有属性,直接返回子节点值(简化结构)
    if (count($result) === 1 && !str_starts_with(key($result), '@')) {
        return reset($result);
    }
    
    return $result;
}

关键改进点

  • 新增了convertNodeToArray递归方法,专门处理节点到数组的转换,逻辑更清晰
  • 核心判断:当发现重复的节点键时,自动将其转换为数组类型,把所有同节点的值都存进去
  • 处理了文本节点的空值过滤,避免生成无效的空字符串
  • 支持XML属性的解析,属性键会以@开头区分(比如<item id="1">会生成['@id' => '1', ...])
  • 可选的简化逻辑:如果节点只有一个子节点且无属性,直接返回子节点值,避免多层嵌套

示例效果

比如你有这样的XML:

<order>
    <items>
        <item>Apple</item>
        <item>Banana</item>
        <item>Cherry</item>
    </items>
</order>

转换后的数组会是:

[
    'items' => [
        'item' => ['Apple', 'Banana', 'Cherry']
    ]
]

完美保留了所有子节点的值。

内容的提问来源于stack exchange,提问作者aborted

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:23:13