为什么我得到SOAP-ERROR:编码:对象没有'税收',在具有嵌套complextype的WSDL中



我必须使用带有PHP的SOAP web服务,并且我得到标题错误。

wsdl的(部分(结构是:

<xs:element name="Obligations" type="tns:ObligationsType"/>
<xs:complexType name="ObligationsType">
<xs:sequence>
<xs:element maxOccurs="99" name="Taxes" type="tns:TaxesType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="TaxesType">
<xs:sequence>
<xs:element name="tax">
<xs:simpleType>
<xs:restriction base="xs:int">
<xs:maxInclusive value="9999"/>
<xs:minInclusive value="1"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="amount">
<xs:simpleType>
<xs:restriction base="xs:double">
<xs:minInclusive value="0.01"/>
<xs:maxInclusive value="9999999999.99"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:complexType>

我发送的关联数组:

$params = array(
'token' => $TOKEN,
'sign' => $SIGN,
'paymentEntity' => 1001,
'form' => array(
'formNumber' => 6042,
'idPaymentType' => 951,
'Obligations' => array (
array( 
'Taxes' => array(
'tax' => 6041,
'amount' => 602.0 
)
)
)
)              
);

我试着用类来做这件事,但我得到了同样的错误。问题来自义务对象。

我试着这样嵌套:

"义务"=>array('tax'=>array('tax'=>1,'amount'=>1.0((我得到无法识别的字段义务

"义务"=>数组('tax'=>1,'amount'=<1.0(我得到的对象没有'tax'属性

"义务"=>数组(数组('tax'=>数组('tax'=>1,'amount'=<1.0((我得到的对象没有"tax"属性

"义务"=>数组('tax'=>数组('tax'=>1((我得到的对象没有"amount"属性

"义务"=>array('Taxes'=>array('amount'=>1((我得到的对象没有'tax'属性

最后一个请求xml

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="...">
<SOAP-ENV:Body>
<ns1:createForm>
<ns1:token>********</ns1:token>
<ns1:sign>********</ns1:sign>
<ns1:paymentEntity>1001</ns1:paymentEntity>
<ns1:form>
<ns1:formNumber>6042</ns1:formNumber>
<ns1:idPaymentType>951</ns1:idPaymentType>
<ns1:Obligations>
<ns1:Taxes>
<tax>6041</tax>
<amount>602.0</amount>
</ns1:Taxes>
</ns1:Obligations>
</ns1:form>
</ns1:createForm>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

结构

"createFormResponse createForm(createForm $parameters)" [2]=> string(74)
"struct createForm { string token; string sign; int paymentEntity; FormType form; }" 
"struct FormType { formNumber formNumber; idPaymentType idPaymentType; Obligations ObligationsType; }"
"struct ObligationsType { TaxesType Taxes; }"
"struct TaxesType { tax tax; amount amount; }" 

我有一个请求示例,它与我获得的示例相同。它只注意

税收。此属性为列表类型。

税款金额。此属性为列表类型。

但它已经在wsdl中标记了。

如果有任何建议,我将不胜感激。关于

处理复杂类型时最好使用对象。它更干净,更容易处理。以下示例提示如何使用php处理复杂类型。

/**
* Entity from complex type ObligationsType
* @see xsd:complexType "ObligationsType"
*/ 
class ObligationsType
{
/**
* Is an array because the containing 'TaxtesType' can appear up to 99 times
* @var ArrayObject
*/
protected $Taxes;
public function getTaxes() : ArrayObject
{
return $this->Taxes;
}
public function setTaxes(TaxesType $taxes) : ObligationsType
{
if ($this->Taxes === null) {
$this->Taxes = new ArrayObject();
}
$this->Taxes->append($taxes);
return $this;
}
public function encode() :SoapVar
{
$container = new ArrayObject();
foreach (get_obect_vars($this) as $property) {
if ($property instanceof ArrayObject) {
foreach ($property as $element) {
$container->append($element);
}
} else {
$container->append($property);
}
}
return new SoapVar(
$container, 
SOAP_ENC_OBJ, 
null, 
null, 
'Obligations',
'http://www.example.com/namespace/tns'
);
}
}
class TaxesType
{
protected $tax;
protected $amount;
public function getTax() : int
{
return $this->tax;
}
public function setTax(int $tax) : TaxesType
{
$this->tax = $tax;
return $this;
}
public function getAmount() : float
{
return $this->amount;
}
public function setAmount(float $amount) : TaxesType
{
$this->amount = $amount;
return $this;
}
public function encode() : SoapVar
{
return new SoapVar(
$this,
SOAP_ENC_OBJ,
null,
null,
'Taxes',
'http://www.example.com/namespace/tns'
);
}
}

现在我们得到了wsdl als PHP实体类中描述的两种复杂类型。这些类所做的唯一一件事就是保存我们的数据并对其进行编码,以便通过soap客户端类发送数据。

如何使用

只需告诉您的soap客户端类,您有用于预期数据的类。soap客户端具有用于此目的的选项classmap

$client = new SoapClient(
$path_to_your_wsdl,
[
'class_map' => [
'ObligationsType' => ObligationsType::class,
'TaxesType' => TaxesType::class,
],
'exceptions' => true,
'trace' => true,
],
);
$tax1 = (new TaxesType())
->setTax(19)
->setAmount(49.99)
->encode();
$tax2 = (new TaxesType())
->setTax(7)
->setAmount(29.49)
->encode();
$obligations = (new ObligationsType())
->setTaxes($tax1)
->setTaxes($tax2)
->encode();
$result = $client->YourWebserviceFunction($obligations);

这个简单的代码片段应该解释xsd复杂类型如何与phpsoap客户端一起工作。形象地说,每个复杂类型都是一个类,其成员是为该复杂类型描述的。这种理解使处理soap请求和响应中的数据变得容易。此外,每个webservice函数都有一个wsdl或任何绑定xsd文件中描述的返回类型。找到这个返回类型,用它创建一个php类,并在soap客户端的classmap选项中提及它。soap客户端可以很容易地在返回类型类中对请求的返回进行水合,这在classmap选项中有所提及。

正如您所看到的,SOAP和PHP可以很好地协同工作。

永远记住:上面显示的代码没有经过测试。请不要在生产中使用此代码。

编辑:如何获取try/catch块中的最后一个请求

正如你在这个答案下面的评论中提到的,你无法获得最后一个请求。我将在接下来的几行中向您展示如何做到这一点。只需将soap客户端init封装在try-catch块中即可。如果soap客户端已初始化,那么catch块中也可以访问它。

try {
$client = new SoapClient(
$wsdl_path,
$options
);
// call of your webservice methods here
...
} catch (SoapFault $e) {
// get the last request in the catch block
if ($client !== null) {
echo "<pre>";
var_dump(htmlentities($client->__getLastRequest()));
echo "</pre>";
}
}

不要忘记将trace选项设置为true。如果没有,则不能调用soap客户端的__getLastRequest()方法。

请使用最后一个xml请求编辑您的问题。

最新更新