Using xpath on a PHP SimpleXML object, SOAP + name

2020-02-01 07:08发布

问题:

After researching this on SO and google for hours now... I hope to get some help here: (I am just one step away from running a regex to remove the namespaces completely)

First this is the XML:

<?xml version="1.0" encoding="utf-16"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header xmlns="http://webservices.site.com/definitions">
    <SessionId>0119A|1</SessionId>
  </soap:Header>
  <soap:Body>
    <Security_AuthenticateReply xmlns="http://xml.site.com/QQ">
      <processStatus>
        <statusCode>P</statusCode>
      </processStatus>
    </Security_AuthenticateReply>
  </soap:Body>
</soap:Envelope>

Now this is what my code in PHP looks like:

$response = simplexml_load_string( $str ,NULL, 
false, "http://schemas.xmlsoap.org/soap/envelope/" );
// just making sure the name space is "registered"
// but I tested all examples also with this removed
$response->registerXPathNamespace("soap",
    "http://schemas.xmlsoap.org/soap/envelope/");
$_res = $response->xpath('//soap:Header');
print_r($_res);
/*** result: simple query for the root "soap" namespace, this looks good! (so far..)
Array
(
    [0] => SimpleXMLElement Object
        (
            [SessionId] => 0119A|1
        )

)
***/

// now we query for the "SessionId" element in the XML
$_res = $response->xpath('//soap:Header/SessionId');
print_r($_res);
/*** result: this does not return anything!
Array
(
)
***/

// another approach
$_res = $response->xpath('//soap:Header/SessionId/text()');
print_r($_res);
/*** result: this does not return anything at all!
***/

// Finally, without using XPath this does work
$_res = $response->xpath('//soap:Header');
$_res = (string)$_res[0]->SessionId;
echo $_res;
/*** result: this worked
0119A|1
***/

How can I get the SOAP message working with XPATH???

Thanks, Roman

回答1:

The multiple namespaces are messing with it, adding the following works for me

$response->registerXPathNamespace("site", "http://webservices.site.com/definitions");
$_res = $response->xpath('//site:SessionId');

also, see this previous stack overflow question



回答2:

You need to register the default namespace used by <SessionId> element as well. Because <SessionId> is in the default namespace it does not have any prefix but in order to your XPath to work, you need to bind also this namespace to some prefix and then use that prefix in your XPath expression.

$response->registerXPathNamespace("ns",
    "http://webservices.site.com/definitions");
$_res = $response->xpath('//soap:Header/ns:SessionId');

XPath (1.0) expressions without a namespace prefix always match only to targets in no-namespace.