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

如何使用PHP Soap消费OTA WSDL?请求异常问题求助

解决OTA WSDL调用中的XML结构错误与Dispatch方法问题

咱们直接针对你遇到的两个核心问题来拆解解决:

问题1:数组生成错误的<item>/<key>/<value>标签

PHP的SoapClient在处理关联数组时,如果没有明确指定元素的命名空间和结构,会默认把关联数组序列成item/key/value这种通用结构,但OTA的WSDL要求严格遵循它的Schema定义,所以得调整数组的构建方式,或者用SoapVar来明确指定每个元素的类型和命名空间。

修复方案:使用正确的数组结构+SoapVar指定命名空间

你需要确保每个嵌套元素都符合OTA Schema的要求,并且给关键元素指定对应的命名空间(也就是http://www.opentravel.org/OTA/2003/05)。试试下面的代码:

$client = new \SoapClient('myservice?wsdl', array('trace' => true));

// 构建RequestorID,用SoapVar指定命名空间和元素名
$requestorId = new \SoapVar([
    'ID' => 'myID',
    'MessagePassword' => 'myPASSWORD',
    'CompanyName' => 'WEB001'
], SOAP_ENC_OBJECT, null, null, 'RequestorID', 'http://www.opentravel.org/OTA/2003/05');

$source = new \SoapVar([$requestorId], SOAP_ENC_OBJECT, null, null, 'Source', 'http://www.opentravel.org/OTA/2003/05');
$pos = new \SoapVar([$source], SOAP_ENC_OBJECT, null, null, 'POS', 'http://www.opentravel.org/OTA/2003/05');

// 构建VehRentalCore的属性和子元素
$pickUpLocation = new \SoapVar([], SOAP_ENC_OBJECT, null, null, 'PickUpLocation', 'http://www.opentravel.org/OTA/2003/05');
$pickUpLocation->LocationCode = 'CODE';

$returnLocation = new \SoapVar([], SOAP_ENC_OBJECT, null, null, 'ReturnLocation', 'http://www.opentravel.org/OTA/2003/05');
$returnLocation->LocationCode = 'CODE';

$vehRentalCore = new \StdClass();
$vehRentalCore->PickUpDateTime = '2018-05-25T08:30:00+00:00';
$vehRentalCore->ReturnDateTime = '2018-05-26T08:30:00+00:00';
$vehRentalCore->PickUpLocation = $pickUpLocation;
$vehRentalCore->ReturnLocation = $returnLocation;

$vehAvailRQCore = new \SoapVar([$vehRentalCore], SOAP_ENC_OBJECT, null, null, 'VehAvailRQCore', 'http://www.opentravel.org/OTA/2003/05');

// 组装最终的请求参数
$request = new \SoapVar([
    'POS' => $pos,
    'VehAvailRQCore' => $vehAvailRQCore
], SOAP_ENC_OBJECT, null, null, 'OTA_VehAvailRateRQ', 'http://www.opentravel.org/OTA/2003/05');

$result = $client->__soapCall('OTA_VehAvailRate', ['OTA_VehAvailRateRQ' => $request]);

这样做的核心是用SoapVar明确告诉SoapClient每个元素的命名空间和元素名称,避免它自动生成通用的item结构。

问题2:使用XSD_ANYXML时的Cannot find dispatch method错误

这个错误是因为你直接把XML字符串作为参数传递,但没有把它包裹在对应方法的参数键下,而且XSD_ANYXML的使用需要确保命名空间正确匹配。

修复方案:正确包裹XML到方法参数中

调整你的代码,把XML放在对应方法的参数数组里,并且确保命名空间正确:

$client = new \SoapClient('myservice?wsdl', array('trace' => true));

$data = '<OTA_VehAvailRateRQ xmlns="http://www.opentravel.org/OTA/2003/05">
<POS>
<Source>
<RequestorID ID="myID" MessagePassword="myPASSWORD">
<CompanyName>WEB001</CompanyName>
</RequestorID>
</Source>
</POS>
<VehAvailRQCore>
<VehRentalCore PickUpDateTime="2018-05-25T08:30:00+00:00" ReturnDateTime="2018-05-26T08:30:00+00:00">
<PickUpLocation LocationCode="APR" />
<ReturnLocation LocationCode="APR" />
</VehRentalCore>
</VehAvailRQCore>
</OTA_VehAvailRateRQ>';

// 用SoapVar包装XML
$soapBody = new \SoapVar($data, \XSD_ANYXML);

// 关键:把SoapVar放在对应方法的参数键下,匹配WSDL里的参数定义
$result = $client->__soapCall('OTA_VehAvailRate', ['OTA_VehAvailRateRQ' => $soapBody]);

注意XML里必须加上xmlns="http://www.opentravel.org/OTA/2003/05"命名空间,否则服务端无法识别元素归属。

额外建议:使用WSDL生成实体类

对于复杂的OTA Schema,手动构建数组和SoapVar很容易出错,推荐使用工具(比如wsdl2phpgenerator或者IDE自带的WSDL生成功能)把OTA的WSDL生成对应的PHP实体类,这样你可以直接实例化类来构建请求,结构更清晰,也不容易出错。

比如用wsdl2phpgenerator的命令:

wsdl2phpgenerator --wsdl=myservice?wsdl --output-dir=./ota_classes

生成后直接用类来构建请求:

$request = new OTA_VehAvailRateRQ();
// 给每个属性赋值,比如$request->POS = new POS(); 以此类推
$result = $client->OTA_VehAvailRate($request);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:07:27