PHP SoapClient生成含重复instrument节点的XML问题求助
解决PHP SoapClient生成重复instrument节点的问题
我明白你现在遇到的困扰:要生成包含多个重复<ns1:instrument>节点的SOAP请求XML,但PHP关联数组没法存储相同键,尝试用SoapVar后<ns1:instruments>节点还变成空的了——这个坑我之前也踩过,咱们一步步来解决。
先回顾下你需要生成的目标XML:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://services.bloomberg.com/datalicense/dlws/ps/20071001"> <SOAP-ENV:Body> <ns1:submitGetHistoryRequest> <ns1:headers> <ns1:daterange> <ns1:period> <ns1:start>2018-05-08</ns1:start> <ns1:end>2018-05-08</ns1:end> </ns1:period> </ns1:daterange> </ns1:headers> <ns1:fields> <ns1:field>PX_LAST</ns1:field> </ns1:fields> <ns1:instruments> <ns1:instrument> <ns1:id>US0000000002</ns1:id> <ns1:yellowkey>Equity</ns1:yellowkey> <ns1:type>ISIN</ns1:type> </ns1:instrument> <ns1:instrument> <ns1:id>US0000000001</ns1:id> <ns1:yellowkey>Equity</ns1:yellowkey> <ns1:type>ISIN</ns1:type> </ns1:instrument> </ns1:instruments> </ns1:submitGetHistoryRequest> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
你之前的代码问题出在两个核心点:
- 直接给
$options->instruments赋值数组,SOAP期望<ns1:instruments>节点下包含多个<ns1:instrument>子节点,正确结构应该是instruments对象拥有一个instrument属性,这个属性是数组。 - SoapVar的命名空间用错了,你用了
http://soapinterop.org/xsd,但必须匹配目标服务的命名空间http://services.bloomberg.com/datalicense/dlws/ps/20071001,且类型名称应该是instrument而非stdClass。
方法一:修正SoapVar的使用方式
调整你原来的代码,修正结构和命名空间:
$options = new \stdClass(); $options->headers = new \stdClass(); $options->headers->daterange = new \stdClass(); $options->headers->daterange->period = new \stdClass(); $options->headers->daterange->period->start = '2018-05-08'; $options->headers->daterange->period->end = '2018-05-08'; $options->fields = new \stdClass(); $options->fields->field = 'PX_LAST'; // 先创建instruments对象,内部的instrument属性是数组 $options->instruments = new \stdClass(); $options->instruments->instrument = []; // 第一个instrument $instrument1 = new \stdClass(); $instrument1->id = 'US0000000002'; $instrument1->type = 'ISIN'; $instrument1->yellowkey = 'Equity'; $options->instruments->instrument[] = new \SoapVar( $instrument1, SOAP_ENC_OBJECT, 'instrument', 'http://services.bloomberg.com/datalicense/dlws/ps/20071001', // 正确的目标命名空间 'instrument' ); // 第二个instrument $instrument2 = new \stdClass(); $instrument2->id = 'US0000000001'; $instrument2->type = 'ISIN'; $instrument2->yellowkey = 'Equity'; $options->instruments->instrument[] = new \SoapVar( $instrument2, SOAP_ENC_OBJECT, 'instrument', 'http://services.bloomberg.com/datalicense/dlws/ps/20071001', 'instrument' ); // 初始化SoapClient并调用方法 $client = new \SoapClient(null, [ 'location' => '你的实际服务地址', 'uri' => 'http://services.bloomberg.com/datalicense/dlws/ps/20071001', 'trace' => true, // 开启trace以便查看生成的请求XML ]); $result = $client->submitGetHistoryRequest($options); // 查看生成的请求XML echo $client->__getLastRequest();
方法二:直接用数组结构(更简洁)
其实不需要用SoapVar,只要数组结构正确,SoapClient会自动把数组转换成重复的节点:
$requestParams = [ 'headers' => [ 'daterange' => [ 'period' => [ 'start' => '2018-05-08', 'end' => '2018-05-08' ] ] ], 'fields' => [ 'field' => 'PX_LAST' ], 'instruments' => [ 'instrument' => [ [ 'id' => 'US0000000002', 'type' => 'ISIN', 'yellowkey' => 'Equity' ], [ 'id' => 'US0000000001', 'type' => 'ISIN', 'yellowkey' => 'Equity' ] ] ] ]; $client = new \SoapClient(null, [ 'location' => '你的实际服务地址', 'uri' => 'http://services.bloomberg.com/datalicense/dlws/ps/20071001', 'trace' => true, 'use' => SOAP_LITERAL, // 确保使用字面量模式,避免序列化异常 ]); // 用SoapParam包装参数,指定参数名称 $result = $client->submitGetHistoryRequest(new \SoapParam($requestParams, 'submitGetHistoryRequest')); // 查看生成的XML echo $client->__getLastRequest();
这两种方法都能生成你需要的包含多个<ns1:instrument>节点的XML,第二种方法更简洁,推荐优先使用。
内容的提问来源于stack exchange,提问作者ზურა კუპატაძე
相关产品推荐
相关产品推荐

