如何用PHP的SimpleXMLElement生成指定格式的XML?
使用PHP SimpleXMLElement生成指定命名空间XML的正确方法
问题概述
需要从关联数组生成带多命名空间的指定结构XML,使用SimpleXMLElement时遇到以下问题:
- 子元素命名空间错误,默认继承根元素的
pt命名空间而非指定的request_meta - 布尔值
false被生成自闭合标签,不符合目标结构 - 操作过程中丢失XML声明和根元素
<pt:request>
目标XML结构
<pt:request xmlns:pt="urn:logalty:schemas:core:1.0" xmlns:identity="urn:logalty:schemas:core:identity:1.0" xmlns:process_meta="urn:logalty:schemas:process:meta:1.0" xmlns:ptforms="urn:logalty:schemas:forms:1.0" xmlns:request_meta="urn:logalty:schemas:request:meta:1.0"> <pt:request_meta> <request_meta:service>PT0005_ACCEPTANCEXPRESS</request_meta:service> <request_meta:time2close unit="d" value="28"/> <request_meta:time2save unit="d" value="1825"/> <request_meta:lopd>0</request_meta:lopd> <request_meta:retryprotocol>3</request_meta:retryprotocol> <request_meta:synchronous>false</request_meta:synchronous> <request_meta:tsa>0</request_meta:tsa> <request_meta:userdefined name="LGT_SDKJava">4.13.2</request_meta:userdefined> </pt:request_meta> </pt:request>
关联数组数据源
$logalty_data = [ 'request_meta:service' => 'instalacion_id_'.$id, 'request_meta:time2close unit="d" value="28"' => '', 'request_meta:time2save unit="d" value="1825"' => '', 'request_meta:lopd' => 0, 'request_meta:retryprotocol' => 3, 'request_meta:synchronous' => false, 'request_meta:tsa' => 0, 'request_meta:userdefined name="php"' => '8.1.6' ];
当前错误输出
<pt:request_meta> <pt:service>instalacion_id_1</pt:service> <pt:time2close unit="d" value="28"/> <pt:time2save unit="d" value="1825"/> <pt:lopd>0</pt:lopd> <pt:retryprotocol>3</pt:retryprotocol> <pt:synchronous/> <pt:tsa>0</pt:tsa> <pt:userdefined name="php">8.1.6</pt:userdefined> </pt:request_meta>
解决方案
关键处理要点
- 显式管理命名空间:创建元素时必须指定对应的命名空间URI,不能依赖自动继承
- 拆分标签与属性:手动解析数组键中的标签名和属性部分,避免混写导致解析错误
- 特殊值处理:将布尔值转为字符串,避免生成不符合要求的自闭合标签
- 格式化输出:借助DOMDocument保留XML声明和缩进格式
完整实现代码
<?php $id = 1; $logalty_data = [ 'request_meta:service' => 'instalacion_id_' . $id, 'request_meta:time2close unit="d" value="28"' => '', 'request_meta:time2save unit="d" value="1825"' => '', 'request_meta:lopd' => 0, 'request_meta:retryprotocol' => 3, 'request_meta:synchronous' => false, 'request_meta:tsa' => 0, 'request_meta:userdefined name="php"' => '8.1.6' ]; // 定义所有命名空间映射 $namespaces = [ 'pt' => 'urn:logalty:schemas:core:1.0', 'identity' => 'urn:logalty:schemas:core:identity:1.0', 'process_meta' => 'urn:logalty:schemas:process:meta:1.0', 'ptforms' => 'urn:logalty:schemas:forms:1.0', 'request_meta' => 'urn:logalty:schemas:request:meta:1.0' ]; // 创建带完整命名空间的根元素 $root = new SimpleXMLElement( '<pt:request xmlns:pt="' . $namespaces['pt'] . '" xmlns:identity="' . $namespaces['identity'] . '" xmlns:process_meta="' . $namespaces['process_meta'] . '" xmlns:ptforms="' . $namespaces['ptforms'] . '" xmlns:request_meta="' . $namespaces['request_meta'] . '"/>' ); // 创建pt:request_meta元素(归属pt命名空间) $requestMeta = $root->addChild('pt:request_meta', '', $namespaces['pt']); foreach ($logalty_data as $key => $value) { // 拆分命名空间前缀和标签内容 list($prefix, $tagPart) = explode(':', $key, 2); // 解析标签名和属性 $tagName = $tagPart; $attributes = []; if (strpos($tagPart, ' ') !== false) { list($tagName, $attrStr) = explode(' ', $tagPart, 2); // 正则提取属性键值对 preg_match_all('/(\w+)="([^"]+)"/', $attrStr, $matches); $attributes = array_combine($matches[1], $matches[2]); } // 获取当前命名空间的URI $nsUri = $namespaces[$prefix]; // 创建指定命名空间的子元素 $element = $requestMeta->addChild($prefix . ':' . $tagName, '', $nsUri); // 添加元素属性 foreach ($attributes as $attrName => $attrValue) { $element->addAttribute($attrName, $attrValue); } // 处理文本内容:布尔值转字符串,空值跳过(保持自闭合) if ($value !== '') { $element[0] = is_bool($value) ? ($value ? 'true' : 'false') : $value; } } // 转换为DOMDocument以保留XML声明和格式化输出 $dom = dom_import_simplexml($root)->ownerDocument; $dom->formatOutput = true; echo $dom->saveXML(); ?>
代码说明
- 根元素初始化时显式声明所有命名空间,确保XML结构完整
- 遍历数组时拆分每个键的命名空间、标签名和属性,分别处理
- 创建子元素时指定对应命名空间URI,确保标签前缀正确
- 对布尔值
false做字符串转换,避免生成自闭合标签 - 使用DOMDocument格式化XML,输出带声明和缩进的标准结构
内容的提问来源于stack exchange,提问作者scorpions77
相关产品推荐
相关产品推荐

