如何用PHP SoapClient构建含complexType sequence any的SOAP请求及疑问
关于SoapClient与WSDL匹配问题的解答
我来帮你逐个拆解这些疑问,结合你给出的WSDL片段和服务端要求的请求格式来看:
1. 为何Bar>Bar>Qux未出现在WSDL中?
你的WSDL里,<s:element name="Bar">的complexType定义里用了<s:any/>——这是XML Schema的通配符元素,作用就是允许这个节点包含任何未在WSDL的schema里定义的XML内容。服务端要求的嵌套<Bar>和<Qux>属于他们自定义的内部结构,并没有在WSDL中明确声明,只是借由<any>节点来允许任意内容传入。
2. 为何存在两层Bar节点?这是否属于设计缺陷?
两层<Bar>确实有点反直觉:
- 第一层
<Bar>是WSDL里明确定义的请求参数节点; - 第二层
<Bar>是服务端额外要求的嵌套容器节点。
这大概率属于服务端的设计瑕疵,因为WSDL里的<Bar>已经是一个可以承载任意内容的容器,完全没必要再套一层同名节点。这种冗余设计可能是服务端内部数据结构直接映射到SOAP请求时的遗留问题。
3. 为何需要使用节点?
PHP的SoapClient是严格按照WSDL的结构来生成请求的。你的WSDL里,<Bar>的complexType下明确声明了<s:any/>,意味着这个节点的内容必须对应到客户端请求参数里的any键——SoapClient会把这个键对应的值解析为<any>节点承载的自定义XML内容。如果不用any键,客户端不知道如何处理WSDL中未定义的嵌套节点,就会抛出你遇到的编码错误。
4. 是否存在无需内联XML即可构建请求的方法?
有的,你可以用SoapVar类来构造这部分嵌套结构,不用手动写内联XML字符串,示例代码如下:
// 先构造内层的<Qux>节点所在的<Bar> $innerBar = new \SoapVar( ["Qux" => "bar_qux_value"], SOAP_ENC_OBJECT, null, null, "Bar", "[redacted]" // 替换为WSDL里的targetNamespace值 ); // 再构造外层的<Bar>,对应WSDL定义的节点 $outerBar = new \SoapVar( $innerBar, SOAP_ENC_OBJECT, null, null, "Bar", "[redacted]" // 同样替换为targetNamespace ); // 发起请求 $client = new \SoapClient($url_to_wsdl); $result = $client->GetResult([ "Foo" => "foo_value", "Bar" => ["any" => $outerBar] ]);
SoapVar可以帮你指定节点名称、命名空间,让SoapClient正确生成符合服务端要求的嵌套XML结构,避免手动拼接XML的麻烦。
内容的提问来源于stack exchange,提问作者Halcyon
相关产品推荐
相关产品推荐

