PHP SoapClient不处理WSDL中的abstract和substitutionGroup属性

时间:2015-12-10 20:50:16

标签: php soap wsdl soap-client

我正在使用他们提供的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

1 个答案:

答案 0 :(得分:1)

我不得不覆盖和扩展php SoapClass。它与php soapclass有关,期望请求/响应中的某种格式然后接收/发送的内容。扩展它允许我自己处理格式化。

wsdl没有错,错误是类的一部分。无法绕过覆盖