PHP SOAP服务返回同名带属性元素数组的格式匹配问题
解决PHP SOAP服务返回与输入一致的带属性XML结构问题
我完全懂你碰到的麻烦——当你直接返回PHP解析后的SOAP请求对象时,原本带多个属性的<policy>元素居然变成了空标签,完全没保留原来的结构和属性值。这是因为PHP的SOAP扩展默认的对象序列化逻辑,没办法正确识别那些从XML属性转换来的对象属性,得手动用SoapVar来构建响应结构才行。
问题根源
PHP解析SOAP请求时,会把带属性的XML元素(比如你的<policy>)转换成带对应属性的stdClass对象,但返回响应时,SOAP扩展默认只会把数组当成重复元素处理,却不会自动把对象里的属性映射回XML元素的属性,所以才生成了空的<policy />标签。
解决方案:手动构建带属性的SOAP响应
我们需要遍历每个policy对象,把它们转换成带属性的SoapVar,再把整个响应结构正确包装,这样就能生成和输入一致的XML了。
方法1:PHP 8.0+ 版本(支持SoapAttribute)
<?php class Example { public function SendPolicies($request) { // 处理每个policy对象,转换为带属性的SoapVar $policySoapVars = []; foreach ($request->policy as $policy) { // 注意:解析时polizzenNr被转成了Nr,这里要修正回原属性名 $attributes = []; foreach ($policy as $key => $value) { $attributeName = $key === 'Nr' ? 'polizzenNr' : $key; $attributes[] = new SoapAttribute($attributeName, '', $value); } // 创建带属性的policy元素SoapVar $policyVar = new SoapVar( '', // policy元素没有子节点,内容为空 XSD_ANYXML, null, null, 'policy', 'https://customer-soap.example.com/?WSDL', // 对应你的命名空间 $attributes ); $policySoapVars[] = $policyVar; } // 构建完整的响应结构 $responseData = [ 'sesid' => new SoapVar( $request->sesid, XSD_STRING, null, null, 'sesid', 'https://customer-soap.example.com/?WSDL' ), 'policy' => $policySoapVars ]; // 包装成输出对应的根元素 $response = new SoapVar( $responseData, SOAP_ENC_OBJECT, null, null, 'SendPoliciesRequestOutput', 'https://customer-soap.example.com/?WSDL' ); return $response; } }
方法2:兼容PHP 8.0以下版本(手动构造XML片段)
如果你的PHP版本低于8.0,没有SoapAttribute类,可以直接用XSD_ANYXML构造XML字符串:
<?php class Example { public function SendPolicies($request) { $policySoapVars = []; foreach ($request->policy as $policy) { // 构建属性字符串 $attrString = ''; foreach ($policy as $key => $value) { $attributeName = $key === 'Nr' ? 'polizzenNr' : $key; // 转义XML特殊字符,避免格式错误 $attrString .= " $attributeName=\"" . htmlspecialchars($value, ENT_QUOTES) . "\""; } // 直接构造policy元素的XML $policyXml = "<policy$attrString />"; $policySoapVars[] = new SoapVar($policyXml, XSD_ANYXML); } // 构建响应 $responseXml = '<SendPoliciesRequestOutput xmlns="https://customer-soap.example.com/?WSDL">'; $responseXml .= "<sesid>" . htmlspecialchars($request->sesid, ENT_QUOTES) . "</sesid>"; $responseXml .= implode('', $policySoapVars); $responseXml .= '</SendPoliciesRequestOutput>'; return new SoapVar($responseXml, XSD_ANYXML); } }
关键注意点
- 一定要修正属性名:你的请求里
polizzenNr被PHP解析成了Nr,所以在构建响应时要把这个属性名改回去,否则返回的XML属性名会不对。 - 记得转义XML特殊字符:如果属性值里包含
<、>、"等字符,必须用htmlspecialchars转义,避免生成无效的XML。
这样处理后,你的SOAP服务返回的XML就会和输入的结构完全一致,包含所有带属性的<policy>元素啦。
内容的提问来源于stack exchange,提问作者Theo
相关产品推荐
相关产品推荐

