从SOAPClient Response解析命名空间

时间:2013-02-06 20:02:37

标签: xml soap xml-namespaces soap-client

好的,所以我让SOAPClient拨打电话。如果我使用__getLastResponse(),我会在我的XML中得到一行:

<Discount xsi:type="ProgressivePromotion" from="2013-05-05T00:00:00" to="2013-05-14T00:00:00" type="Percent" value="20" name="Special Deal"/>

但是,我的SOAPClient类中的函数返回一个对象。

PHP类中调用的代码是:

function SearchHotels($parameters ){
$funcRet = null;
try {
    $funcRet = $this->client->SearchHotels($parameters);
} catch ( Exception $e ) {
    echo "(SearchHotels) SOAP Error:\n-------------------------------------\n" . $e->getMessage () . "\n\n";
    echo "(SearchHotels) Request:\n-------------------------------------\n" . $this->client->__getLastRequest() . "\n\n";
    echo "(SearchHotels) Response:\n-------------------------------------\n" . $this->client->__getLastResponse() . "\n\n";
}
return $funcRet; 
}

当我使用返回的对象时,我可以从Discount元素中访问以下属性:

类型:ProgressivePromotion
来自:2013-05-05T00:00:00
至:2013-05-14T00:00:00
价值:20
名称:特殊交易

但我无法访问type =“Percent”

似乎SOAPClient忽略xsi:type中的xsi名称空间,只将该属性存储为 type

那么如何访问xsi:type AND type以便我可以判断我的折扣是百分比还是金额还是其他任何类型?

BTW,在我的SOAP响应的顶部,我没有看到任何声明xsi是什么。

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <SearchHotelsResponse xmlns="http://tourico.com/webservices/hotelv3">
            <SearchHotelsResult>
                <Info xmlns="http://schemas.tourico.com/webservices/hotelv3" version="9.71" culture="en-US" serverTime="2013-02-06T14:49:58.3500117-05:00"/>
                   <HotelList xmlns="http://schemas.tourico.com/webservices/hotelv3">

修改

如果我var_dump返回的对象,我得到

stdClass Object
(
[SearchHotelsResult] => stdClass Object
    (
        [Info] => stdClass Object
            (
                [version] => 9.71
                [culture] => en-US
                [serverTime] => 2013-02-06T15:17:59.8445748-05:00
            )

        [HotelList] => stdClass Object
            (
                [Hotel] => Array
                    (
                        [0] => stdClass Object
                            [RoomTypes] => stdClass Object
                                    (
                                        [RoomType] => Array
                                            (
                                                [0] => stdClass Object
                                                    (
                                                       [Discount] => stdClass Object
                                                            (
                                                                [from] => 2013-05-05T00:00:00
                                                                [to] => 2013-05-14T00:00:00
                                                                [type] => ProgressivePromotion
                                                                [value] => 20
                                                                [name] => Special Deal
                                                            )

看看我是如何丢失type =“Amount”的?

我不能通过

来调用折扣
echo $result->SearchHotelsResult->HotelList->Hotel[0]->RoomTypes->RoomType[0]->Discounts->type;

因为我得到了

Undefined property: stdClass::$Discounts  Notice: Trying to get property of non-object

所以我将整个对象转换为一个巨大的多维数组并以这种方式访问​​。无论如何, type =“Amount”没有被拉动。

2 个答案:

答案 0 :(得分:1)

我以这种方式解决了这个问题。

<?php
class fixSoapClient extends SoapClient{
    function __doRequest($request, $location, $action, $version, $one_way = 0) {
        $result = parent::__doRequest($request, $location, $action, $version);
        $str = preg_replace('#<Discount xsi:type="ProgressivePromotion"(.+)type="(.+)"(.+)name="(.+)"/>#isU', 
                '<Discount xsi:type="ProgressivePromotion"$1type="wath ever"$3name="$2"/>', $result);
        return $str;
    }   
}

您可以在name属性中找到折扣类型。 因此,您必须实例化SoapClient

,而不是实例化fixSoapClient

答案 1 :(得分:0)

您似乎正在使用名称空间感知XML解析器解析您的响应,但解析器的名称空间支持未启用。这导致了两条规则的冲突。

  1. 使用命名空间解析XML文档时,所有元素和属性都使用其扩展名称引用。扩展名称由名称空间URI和元素/属性的本地名称组成。如果解析器不支持名称空间,则名称的URI部分将丢失。因此,如果未打开名称空间支持,则一些具有名称空间支持的解析器也会删除名称空间前缀。
  2. 不允许元素包含具有相同(扩展)名称的两个属性。在这种情况下,其他一个属性将丢失。通常,名称空间感知XML解析器会将这两个type属性视为{http://www.w3.org/2001/XMLSchema-instance}typetype(使用James Clark表示法)。非名称空间感知解析器应返回属性名称xsi:typetype。在这些情况下,没有名称冲突,一切都应该正常。
  3. 如果您的解析器知道冒号:用作命名空间前缀分隔符但解析器未使用命名空间,因此会丢弃分隔符和命名空间前缀,则会出现问题。然后,由于属性名称唯一性规则,这两个属性都将获得名称type,其中一个属性将丢失/覆盖。

    解决方案:为您的解析器设置命名空间支持,或切换到另一个功能更强的解析器。如果您使用有关如何解析XML文件的信息更新您的问题,希望有人可以提供更具体的答案。