假设我有这个XML(它是一个SOAP调用)
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ext="http://api.movilway.net/schema/extended">
<soapenv:Header/>
<soapenv:Body>
<ext:GetBalanceRequest>
<ext:AuthenticationData>
<ext:Username>Foo</ext:Username>
<ext:Password>Bar$123!password</ext:Password>
<ext:SessionID>as3hy4ri37g2f345</ext:SessionID>
</ext:AuthenticationData>
<ext:DeviceType>3</ext:DeviceType>
</ext:GetBalanceRequest>
</soapenv:Body>
</soapenv:Envelope>
(Foo,Bar$123!password,as3hy4ri37g2f345和3只是示例值)通常,当我想进行简单的SOAP调用时,我会使用这样的SoapClient
:
$sc = new SoapClient('http://my.url/my/service?wsdl');
$result = $sc->someMethod(array('some' => 'params'));
但是这个似乎使用xsd名称空间和嵌套结构。
Q:如何调用带有命名空间前缀的方法(在本例中为ext:)和带有命名空间前缀(和嵌套结构)的参数?
编辑:我所尝试的包括将名称空间作为uri选项。有一个例外:
SoapFault:函数("GetBalanceRequest")不是此服务的有效方法
我试过的代码是这样的:
try {
$client = new SoapClient('http://THEURLHERE/Path/To/The/Service?wsdl', array('uri' => 'http://api.movilway.net/schema/extended'));
print_r($client->GetBalanceRequest(
array(
'AuthenticationData' => array(
'Username' => 'MYUSERHERE',
'Password' => 'MYPASSWORDHERE'
),
'DeviceType' => 1
)
));
} catch(Exception $e) {
print_r($e);
}
假设没有错误或打字错误,因为我直接从文档中获得了所需的XML。
Q+:我必须在代码中添加什么才能发送这样的请求?
首先,正确的术语不是"extension",而是"namespace"——这里的namespace被称为"extended",并且在示例中被赋予了别名ext:
,这只是巧合。
其次,XML名称空间只是表示"这些元素和属性属于特定类型"的一种方式;它不会自动暗示普通XML之外的任何特殊结构——例如,它与XSD没有自动关系。命名空间是由URI唯一标识的,URI实际上不必指向任何地方(有关更多信息,请参阅前面的回答)。在文档中,它被赋予了一个任意的前缀,这样你就不必在每个元素旁边写URI。
SOAP本身使用名称空间http://schemas.xmlsoap.org/soap/envelope/
作为表示SOAP"信封"的元素,这里给出了别名soapenv
。SOAP消息的"主体"不在该名称空间中,因此SOAP服务通常将其元素声明为其他特定名称空间的一部分;如果没有,它们将位于默认的、无名称的命名空间中。
所以,理论就到此为止了。练习:
如果您正在使用WSDL加载web服务,并且该WSDL的格式正确,那么SOAPClient类应该自动向您的请求添加适当的命名空间。由于请求完全存在于该名称空间内,因此无需区分"名称空间http://api.movilway.net/schema/extended
中的AuthenticationData
"answers"AuthenticationData
"。
如果由于某种原因这不起作用,或者您没有WSDL,那么您可能需要创建具有适当名称空间的SoapVar
对象。
然而,根据您刚刚编辑到问题中的错误消息,以上所有内容可能都完全无关,因为问题可能与命名空间无关——您在WSDL模式下操作,而客户端告诉您该方法不存在。所以,对我来说,显而易见的问题是,该方法是否在WSDL文件中明确定义?