我正在使用他们提供的wsdl向Canada Post发送电话,其中包含以下部分:
<!-- group-id and transmit-shipment are mutually exclusive -->
<xsd:element name="groupIdOrTransmitShipment" abstract="true" />
<xsd:element name="group-id" type="tns:GroupIDType" substitutionGroup="tns:groupIdOrTransmitShipment"/>
<xsd:element name="transmit-shipment" type="xsd:boolean" fixed="true" substitutionGroup="tns:groupIdOrTransmitShipment"/>
<xsd:complexType name="ShipmentType">
<xsd:all>
<xsd:element ref="tns:groupIdOrTransmitShipment" />
<xsd:element name="quickship-label-requested" type="xsd:boolean" minOccurs="0"/>
<xsd:element name="cpc-pickup-indicator" type="xsd:boolean" fixed="true" minOccurs="0"/>
<xsd:element name="requested-shipping-point" type="tns:PostalCodeType" minOccurs="0"/>
<xsd:element name="shipping-point-id" type="tns:OutletIDType" minOccurs="0" />
<xsd:element name="expected-mailing-date" type="xsd:date" minOccurs="0"/>
<xsd:element name="delivery-spec" type="tns:DeliverySpecType"/>
<xsd:element name="return-spec" type="tns:ReturnSpecType" minOccurs="0"/>
</xsd:all>
</xsd:complexType>
在他们的代码示例中,他们扩展了Soap类并覆盖了__doRequest()
Soap方法,如下所示:
/*
Need to override SoapClient because the abstract element 'groupIdOrTransmitShipment' is expected to be in the request in order for validation to pass.
So, we give it what it expects, but in __doRequest we modify the request by removing the abstract element and add the correct element.
*/
class MySoapClient extends SoapClient {
function __construct($wsdl, $options = null) {
parent::__construct($wsdl, $options);
}
function __doRequest($request, $location, $action, $version, $one_way = NULL) {
$dom = new DOMDocument('1.0');
$dom->loadXML($request);
//get element name and values of group-id or transmit-shipment.
$groupIdOrTransmitShipment = $dom->getElementsByTagName("groupIdOrTransmitShipment")->item(0);
$element = $groupIdOrTransmitShipment->firstChild->firstChild->nodeValue;
$value = $groupIdOrTransmitShipment->firstChild->firstChild->nextSibling->firstChild->nodeValue;
//remove bad element
$newDom = $groupIdOrTransmitShipment->parentNode->removeChild($groupIdOrTransmitShipment);
//append correct element with namespace
$body = $dom->getElementsByTagName("shipment")->item(0);
$newElement = $dom->createElement($element, $value);
$body->appendChild($newElement);
//save $dom to string
$request = $dom->saveXML();
//echo $request;
//doRequest
return parent::__doRequest($request, $location, $action, $version);
}
}
使用他们的覆盖方法可以正常工作,因为它会改变xml请求,但这对我来说非常困惑 为什么 他们正在这样做。 WSDL是否存在根本性的错误?这是PHP的SoapClient中的错误吗?我想要一种在不覆盖任何核心类方法的情况下发送有效请求的方法。
根据我的理解,作者想要一个group-id
或 transmit-shipment
元素,但不能同时使用这两个元素。由于<choice>
元素中没有<all>
元素,根据this discussion on w3c.org,为此目的声明替换组应该没有问题,并且只包含两个元素中的一个在我的请求中,但如果我只包含transmit-shipment
并省略抽象元素groupIdOrTransmitShipment
php则返回错误:
SOAP-ERROR: Encoding: object has no 'groupIdOrTransmitShipment' property
更新 这是非常古老但可能相关吗? https://bugs.php.net/bug.php?id=48570
答案 0 :(得分:1)
我不得不覆盖和扩展php SoapClass。它与php soapclass有关,期望请求/响应中的某种格式然后接收/发送的内容。扩展它允许我自己处理格式化。
wsdl没有错,错误是类的一部分。无法绕过覆盖