SimpleXML解析嵌套命名空间 - PHP

时间:2013-03-25 18:15:03

标签: php namespaces simplexml

我在解析位于下面的名为“q0:”的嵌套命名空间中的标记时遇到了一个小问题。

//Tag that I am trying to parse
  <q0:CustomerTransactionId>

由于某种原因,我能够访问所有“v12:”命名空间标记,但不能访问“q0:”标记。

谢谢!

这是XML

<?xml version="1.0" encoding="UTF-8"?>
 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
 <env:Header 
       xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<soapenv:Body>
<v12:ProcessShipmentReply 
    xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:v12="http://fedex.com/ws/ship/v12">
    <v12:HighestSeverity>ERROR</v12:HighestSeverity>
    <v12:Notifications>
        <v12:Severity>ERROR</v12:Severity>
        <v12:Source>ship</v12:Source>
        <v12:Code>3058</v12:Code>
        <v12:Message>Recipient Postal code or routing code is required</v12:Message>
        <v12:LocalizedMessage>Recipient Postal code or routing code is required</v12:LocalizedMessage>
    </v12:Notifications>
    <q0:TransactionDetail xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:q0="http://fedex.com/ws/ship/v12">
        <q0:CustomerTransactionId>21445634</q0:CustomerTransactionId>
    </q0:TransactionDetail><q0:Version xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:q0="http://fedex.com/ws/ship/v12">
    <q0:ServiceId>ship</q0:ServiceId>
    <q0:Major>12</q0:Major>
    <q0:Intermediate>0</q0:Intermediate>
    <q0:Minor>0</q0:Minor>
  </q0:Version>
  </v12:ProcessShipmentReply>
  </soapenv:Body>
  </soapenv:Envelope>

这是我的解析

    $xml = simplexml_load_string($result, NULL, NULL, 'http://schemas.xmlsoap.org/soap/envelope/');
    $xml->registerXPathNamespace('env', 'http://schemas.xmlsoap.org/soap/envelope/');
    $xml->registerXPathNamespace('v12', 'http://fedex.com/ws/ship/v12');
    $xml->registerXPathNamespace('q0', 'http://fedex.com/ws/ship/v12');

    $bodies = $xml->xpath('env:Body');

    foreach($bodies as $body){

        $reply = $body->children('v12', TRUE)->ProcessShipmentReply;
        $reply2 = $body->children('q0', TRUE)->TransactionDetail;

        $custInfoArr['status'] = (string) $reply->HighestSeverity;

        if(strtolower($custInfoArr['status'])=="error"){


            $custInfoArr['invoiceNum'] = (string)$reply2->CustomerTransactionId;
            $custInfoArr['notificationSeverity']= (string) $reply->Notifications->Severity;
            $custInfoArr['notificationSource']= (string) $reply->Notifications->Source;
            $custInfoArr['notificationCode']= (string) $reply->Notifications->Code;
            $custInfoArr['notificationMessage']= (string) $reply->Notifications->Message;
            $custInfoArr['notificationLocalizedMessage']= (string) $reply->Notifications->LocalizedMessage;

        }

        $custInfoArr['trackingCode'] = (string) $reply->CompletedShipmentDetail->CompletedPackageDetails->TrackingIds->TrackingNumber;
        $custInfoArr['labelCode'] = (string) $reply->CompletedShipmentDetail->CompletedPackageDetails->Label->Parts->Image;
        $custInfoArr['labelCode'] = base64_decode($custInfoArr['labelCode']);

    }

1 个答案:

答案 0 :(得分:1)

<q0:TransactionDetail>不是<env:Body>的孩子,而是<v12:ProcessShipmentReply>的孩子,因此您需要在$reply内查找,而不是$body$reply2 = $reply->children('q0', TRUE)->TransactionDetail;

要记住的重要一点是,->TagName运算符和->children()方法只能查看特定节点的直接子节点,它们不会“深入”搜索“像XPath。

事实上,v12:q0:都是同一命名空间('http://fedex.com/ws/ship/v12')的别名,因此下一行可以是$reply2 = $reply->TransactionDetail。如果你只是说$reply = $body->children('http://fedex.com/ws/ship/v12')->ProcessShipmentReply而不是依赖别名,那就更清楚了(更安全,因为这些别名可能会改变)。

顺便说一下,除非你将它用于其他东西,否则你也可以摆脱所有的XPath代码(包括所有registerXPathNamespace调用)并写下$body = $xml->children('http://schemas.xmlsoap.org/soap/envelope/')->Body(我很漂亮)确保SOAP每个消息只允许一个Body。)