使用soap响应体的Simplexml和registerxpathnamespace问题

时间:2014-09-29 10:43:03

标签: php xpath namespaces simplexml

这是xml :( a.xml

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
     xmlns:ser="http://www.example.com/v1/services">
    <soapenv:Header/>
    <soapenv:Body>
        <ser:getAnalyticalDeliveryEstimatesRequest>
            <ser:buyer>
                <ser:buyerId>1233</ser:buyerId>
                <ser:toCountry>IN</ser:toCountry>
                <ser:toZip>110001</ser:toZip>
            </ser:buyer>
            <ser:item>
                <ser:id>25164</ser:id>
                <ser:categoryId>15032</ser:categoryId>
                <ser:seller>
                    <ser:sellerId>11997</ser:sellerId>
                    <ser:fromCountry>IN</ser:fromCountry>
                </ser:seller>
                <ser:transactionId>0</ser:transactionId>
            </ser:item>
        </ser:getAnalyticalDeliveryEstimatesRequest>
    </soapenv:Body>
</soapenv:Envelope>

用于解析此问题的PHP代码:

$xml = simplexml_load_file( 'a.xml', NULL, NULL, 'http://schemas.xmlsoap.org/soap/envelope/');
$xml->registerXPathNamespace('soapenv', 'http://schemas.xmlsoap.org/soap/envelope/');
$xml->registerXPathNamespace('ser', 'http://www.example.com/v1/services');

$xpath = $xml->xpath( '//soapenv:Body/ser:getAnalyticalDeliveryEstimatesRequest' );

print_r($xpath);

它没有提供数据。

如果我做错了,请告诉我。

2 个答案:

答案 0 :(得分:2)

首先,在您的示例代码中,您实际上并未在任何地方定义$node

$xpath = $xml->xpath( '//soapenv:Body/ser:getAnalyticalDeliveryEstimatesRequest' );
print_r($node);

应该是:

$xpath = $xml->xpath( '//soapenv:Body/ser:getAnalyticalDeliveryEstimatesRequest' );
$node = $xpath[0];
print_r($node);

或者也许:

$xpath = $xml->xpath( '//soapenv:Body/ser:getAnalyticalDeliveryEstimatesRequest' );
foreach ( $xpath as $node ) {
    print_r($node);
}

其次,print_r在显示SimpleXML对象方面并不出色。它给你一个空输出并不意味着该元素是空的。

例如,尝试回显找到的节点的名称(Demo):

$xpath = $xml->xpath( '//soapenv:Body/ser:getAnalyticalDeliveryEstimatesRequest' );
foreach ( $xpath as $node ) {
    echo $node->getName();
}

要获取其内容,您需要使用the ->children() method选择它们所在的命名空间,此时即使print_r也能看到它们(尽管有其他原因不能依赖它们)完全)(Demo):

$xpath = $xml->xpath( '//soapenv:Body/ser:getAnalyticalDeliveryEstimatesRequest' );
foreach ( $xpath as $node ) {
    print_r( $node->children('http://www.example.com/v1/services') ); 
}

尝试搜索“带名称空间的SimpleXML”以获取更多示例。

答案 1 :(得分:1)

看到那些不起作用很奇怪,但也可以使用它:

$dom = new DOMDocument();
$dom->loadXML($xml);
$xpath = new DOMXpath($dom);
$element = $xpath->query('//soapenv:Body/ser:getAnalyticalDeliveryEstimatesRequest');

foreach($element->item(0)->childNodes as $node) {
    // perform your actions here
}

Sample Output

编辑:这也是另一种方式:

$xml_string ='<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
     xmlns:ser="http://www.example.com/v1/services">
    <soapenv:Header/>
    <soapenv:Body>
        <ser:getAnalyticalDeliveryEstimatesRequest>
            <ser:buyer>
                <ser:buyerId>1233</ser:buyerId>
                <ser:toCountry>IN</ser:toCountry>
                <ser:toZip>110001</ser:toZip>
            </ser:buyer>
            <ser:item>
                <ser:id>25164</ser:id>
                <ser:categoryId>15032</ser:categoryId>
                <ser:seller>
                    <ser:sellerId>11997</ser:sellerId>
                    <ser:fromCountry>IN</ser:fromCountry>
                </ser:seller>
                <ser:transactionId>0</ser:transactionId>
            </ser:item>
        </ser:getAnalyticalDeliveryEstimatesRequest>
    </soapenv:Body>
</soapenv:Envelope>';
$xml = simplexml_load_string($xml_string, null, null, 'http://schemas.xmlsoap.org/soap/envelope/');
$ns = $xml->getNamespaces(true);
$soap = $xml->children($ns['soapenv']);
foreach($soap->Body as $nodes) {
    $ser = $nodes->children($ns['ser'])->getAnalyticalDeliveryEstimatesRequest;
    foreach($ser->buyer as $sub_nodes) { // this can also be ->item as well

    }
}