我遇到了PHP SoapClient的问题。我有以下WSDL https://api.mindbodyonline.com/0_5/DataService.asmx?WSDL,我正在调用SelectDataXml。它返回相应的响应,其中包含一个对象数组,这些对象对应于SQL查询将返回的数据行。我已经在Soap UI和__getLastResponse方法中检查了响应(使用print_r例程和NetBeans调试器窗口)。我可以看到完整的响应作为字符串,但是数组是用空的stdClasses构建的。我在这里看到了几个答案,建议关闭缓存来解决这个问题。我尝试了但没有。我似乎无法找到使其正确构建对象的方法。任何帮助将不胜感激。
EDITED
抽象超类(用'REMOVED'替换的敏感数据):
abstract class Mindbody_service {
protected $_userCredentials = array ( "Username" => 'REMOVED', "Password" => 'REMOVED', 'SiteIDs' => array ( 'REMOVED' ) ),
$_sourceCredentials = array ( "SourceName" => 'REMOVED', "Password" => 'REMOVED', 'SiteIDs' => array ( 'REMOVED' ) ),
$_endPoint;
public function __construct( $wsdl, $options = array () )
{
try {
$this->_endPoint = new SoapClient( $wsdl, $options );
} catch ( SoapFault $fault ) {
echo $fault->getMessage();
}
}
}
具体子类:
include_once ('Mindbody_service.php');
class MindbodyDataServiceResponse {
public $Status,
$ErrorCode,
$XMLDetail,
$ResultCount,
$CurrentPageIndex,
$TotalPageCount,
$Results;
function __construct()
{
$Status = '';
$ErrorCode = 0;
$XMLDetail = '';
$ResultCount = 0;
$CurrentPageIndex = 0;
$TotalPageCount = 0;
$Results = new MindbodyDataServiceResults();
}
}
class MindbodyDataServiceResults {
public $Row;
function __construct()
{
$row = array ();
}
}
class Mindbody_data_service extends Mindbody_service {
private $_query = "Very long SQL command that makes sense to the server";
public function __construct()
{
$wsdl = 'https://api.mindbodyonline.com/0_5/DataService.asmx?wsdl';
$options = array ();
$classMap = array ( 'SelectDataXmlResult' => 'MindbodyDataServiceResponse' );
$options [ 'trace' ] = TRUE;
$options [ 'cache_wsdl' ] = WSDL_CACHE_NONE;
$options [ 'compression' ] = SOAP_COMPRESSION_ACCEPT | SOAP _COMPRESSION_GZIP;
$options [ 'classmap' ] = $classMap;
parent::__construct( $wsdl, $options );
}
public function getSomething( $since = null )
{
$request = array ( 'SourceCredentials' => $this->_sourceCredentials );
$request [ 'SourceCredentials' ] = $this->_sourceCredentials;
$request [ 'UserCredentials' ] = $this->_userCredentials;
$request [ 'XMLDetail' ] = 'Full';
$request [ 'PageSize' ] = 0;
$request [ 'CurrentPageIndex' ] = 0;
$request [ 'SelectSql' ] = $this->_conditionalQuery( $since ) . ' ORDER BY Sales.SaleDate;';
try {
$result = $this->_endPoint->SelectDataXml( array ( 'Request' => $request ) );
} catch ( SoapFault $fault ) {
echo 'ERROR: [' . $fault->faultcode . '] ' . $fault->faultstring . '.';
exit;
} catch ( Exception $e ) {
echo 'ERROR: ' . $e->getMessage() . '.';
exit;
}
echo '<p>';
var_dump ($result->SelectDataXmlResult);
echo '</p>';
return $result->SelectDataXmlResult;
}
}
有问题的方法是getSomething。 $ since变量是无关紧要的,它在查询中用作检索数据的截止日期(我有一个私有_conditionalQuery($ since)方法的原因)。
我在浏览器上看到的var_dump($ result-&gt; SelectDataXmlResult)的输出是:
object(MindbodyDataServiceResponse)[22]
public 'Status' => string 'Success' (length=7)
public 'ErrorCode' => int 200
public 'XMLDetail' => string 'Full' (length=4)
public 'ResultCount' => int 0
public 'CurrentPageIndex' => int 0
public 'TotalPageCount' => int 0
public 'Results' =>
object(stdClass)[23]
public 'Row' =>
array (size=4)
0 =>
object(stdClass)[24]
...
1 =>
object(stdClass)[25]
...
2 =>
object(stdClass)[26]
...
3 =>
object(stdClass)[27]
...
EDITED
这是服务器的回复:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<SelectDataXmlResponse xmlns="http://clients.mindbodyonline.com/api/0_5">
<SelectDataXmlResult>
<Status>Success</Status>
<ErrorCode>200</ErrorCode>
<XMLDetail>Bare</XMLDetail>
<ResultCount>0</ResultCount>
<CurrentPageIndex>0</CurrentPageIndex>
<TotalPageCount>0</TotalPageCount>
<Results>
<Row>
<Column1>REMOVED</Column1>...(more columns)
</Row>
<Row>
<Column1>REMOVED</Column1>...(more columns)
</Row>
<Row>
<Column1>REMOVED</Column1>...(more columns)
</Row>
<Row>
<Column1>REMOVED</Column1>...(more columns)
</Row>
</Results>
</SelectDataXmlResult>
</SelectDataXmlResponse>
</soap:Body>
</soap:Envelope>
由于它是客户数据,我删除了每个Row元素的实际内容,但它们是格式良好的XML元素。这是我作为空stdClass对象得到的那些元素,我应该得到stdClass对象,其成员与Row元素的子元素具有1:1的对应关系。
答案 0 :(得分:1)
找到解决方案!在某些情况下,似乎SoapClient在解析响应时遇到问题。我通过重写getSomething方法来丢弃不正确的结果并使用simplexml_load_string例程来生成对象来解决这个问题。我以线程simplexml_load_string() will not read soap response with "soap:" in the tags为基础。我之前尝试过这个,但是因为我没有考虑到SOAP命名空间冲突(即我单独使用simplexml_load_string:P),因此遇到了问题。这是工作代码:
public function getSoldProducts( $since = null )
{
$request = array ( 'SourceCredentials' => $this->_sourceCredentials );
$request [ 'UserCredentials' ] = $this->_userCredentials;
$request [ 'XMLDetail' ] = 'Full';
$request [ 'PageSize' ] = 0;
$request [ 'CurrentPageIndex' ] = 0;
$request [ 'SelectSql' ] = $this->_conditionalQuery( $since ) . ' ORDER BY Sales.SaleDate;';
try {
$this->_endPoint->SelectDataXml( array ( 'Request' => $request ) );
$xml = simplexml_load_string($this->_endPoint->__getLastResponse ());
$xml->registerXPathNamespace("soap", "http://www.w3.org/2003/05/soap-envelope");
$result = $xml->xpath('//soap:Body');
} catch ( SoapFault $fault ) {
echo 'ERROR: [' . $fault->faultcode . '] ' . $fault->faultstring . '.';
exit;
} catch ( Exception $e ) {
echo 'ERROR: ' . $e->getMessage() . '.';
exit;
}
return $result[0]->SelectDataXmlResponse->SelectDataXmlResult;
}
希望这可以帮助任何有类似问题的人。
答案 1 :(得分:0)
我遇到了类似的情况,几乎拔掉了头发,但最终我把头发整理了下来。
从我无法更改任何东西的Soap服务器上,SoapUI和Java能够获得响应,但是PHP \ SoapClient-> __ soapCall(...)的默认行为是将某些元素作为空的StdClass对象返回。 / p>
我发现的解决方案并不理想,但是可以解决它。
基本上,我需要原始响应,因此我可以自己解析它,并且\ SoapClient-> __ getLastResponse()会这样做,并且前提是我们将选项键'trace'设置为1。
所以,伪代码:
$options = [
// (login, password, etc...)
'trace' => 1,
];
$client = new \SoapClient($wsdl, $options);
// (prepare the data for the call...)
$result = $client->__soapCall('save', [$callContext, $name, $inputXml]);
// Because of trace = 1 in options, this will now work.
$rawResult = $soapClient->__getLastResponse();
现在您可以完全访问响应了,只需解析它即可。
希望这对某人有帮助!