1
votes

So I'm getting an xml file back from a soap service (of which I have no control over). It's returning back an xmlns which is causing simpleXML issues. I'm running a str_replace to get rid of that issue, however now simpleXML just returns an empty object. XML structure appears to be fine, no errors just an empty object.

$xmlString = $client->__getLastResponse();
$feed = str_replace(' xmlns="LMSWebservice"', '', $xmlString);
$sData= simplexml_load_string($feed);

print_r($sData);

Returns: SimpleXMLElement Object()

XML source before str replace is:

<?xml version="1.0" encoding="utf-8"?>
    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <soap:Body>
            <GetUserInternalIDByPersonalIDResponse xmlns="LMSWebservice">
                <GetUserInternalIDByPersonalIDResult>
                    <Response xmlns="">
                        <Timestamp date="24/10/2013" time="04:27:37" />
                        <User>
                           <UserInternalID>4907</UserInternalID>
                        </User>
                    </Response>
                </GetUserInternalIDByPersonalIDResult>
           </GetUserInternalIDByPersonalIDResponse>
       </soap:Body>
  </soap:Envelope>

After str replace:

<?xml version="1.0" encoding="utf-8"?>
    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <soap:Body>
            <GetUserInternalIDByPersonalIDResponse>
                <GetUserInternalIDByPersonalIDResult>
                    <Response xmlns="">
                        <Timestamp date="24/10/2013" time="04:27:37" />
                        <User>
                           <UserInternalID>4907</UserInternalID>
                        </User>
                    </Response>
                </GetUserInternalIDByPersonalIDResult>
           </GetUserInternalIDByPersonalIDResponse>
       </soap:Body>
  </soap:Envelope>

Any help would be greatly appreciated, this is driving me crazy!

----So if I don't get rid of the namespace attribute I get this error message:


Warning: simplexml_load_string() [function.simplexml-load-string]: Entity: line 1: parser warning : xmlns: URI LMSWebservice is not absolute in serviceTest2.php on line 16

Warning: simplexml_load_string() [function.simplexml-load-string]: LSchema"><soap:Body><GetUserInternalIDByPersonalIDResponse xmlns="LMSWebservice" in serviceTest2.php on line 16

Warning: simplexml_load_string() [function.simplexml-load-string]: ^ in serviceTest2.php on line 16

If I try using xPath to get at UserInternalID it returns an empty array. If what you're saying is correct and this is going into simpleXML correctly, then how do I access the UserInternalID node? Sorry, this is the first time using simpleXML and this is just perplexing me.

So just tried changing the NS

$feed = str_replace('xmlns="LMSWebservice"', 'xmlns="ns:LMSWebservice"', $xmlString);

which goes in without errors.

I tried this for the xPath $ID = $sData->xpath('UserInternalID');

I understand this is probably completely wrong, but I haven't tried much else with this as it didn't seem to be going into simpleXML correctly in the first place. :/

So I've used $ID = $sData->xpath('//UserInternalID'); echo $ID[0];

Which works perfectly. Thank you for all your help!

2
You can not say whether or not that object is empty because PHP's SimpleXMLElement does add the properties on the fly (it's done with magic), therefore using var_dump or print_r with SimpleXMLElement does not make much sense. Please see: SimpleXML and print_r() - why is this empty? - which also covers you XML-Namespace related problem of which you thought simplexml could not deal with (which is just wrong to say the way you did).hakre
have added more information in relation to your commentJames Hill
Okay, you are right about the warning, xmlns requires an URI, xmlns="LMSWebservice" does not have such an URI. That actually means that the service you are communicating with is not a SOAP service and in case you want to use it as such you have to tell the service vendor about the problem. Everything else would be unspecified for which you should probably use a proxy. To better recover from the invalid XML, you could replace ' xmlns="LMSWebservice"' with ' xmlns="ns:LMSWebservice"' instead. That (ns:LMSWebservice) is a valid URI then. This maybe already helps you.hakre
And you should an example of how you do the xpath query. You only said that your try does not work, however it's not clear what you try exactly (it's okay to post non-working code if it's clear that it is non working and an example of the try).hakre
ok, just tried what you said, see above for the response I got.James Hill

2 Answers

0
votes

Through the extensive comments and your last edit finally the actual cause of your problem could be revealed, the xpath expression is wrong:

$ID = $sData->xpath('UserInternalID');

Wrong with it is the path, this matches no elements. Instead you could use:

$ID = (string) $xml->xpath('//UserInternalID')[0];

Or more verbose:

$ID = (string) $xml->xpath('//Response/User/UserInternalID')[0];

Key point here is that you write the correct path to the element you would like to query for.

Complete usage example:

<?php
/**
 * SoapClient xml return string with simpleXML
 *
 * @link http://stackoverflow.com/q/19556414/367456
 */

$response = <<<RESPONSE
<?xml version="1.0" encoding="utf-8"?>
    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <soap:Body>
            <GetUserInternalIDByPersonalIDResponse xmlns="LMSWebservice">
                <GetUserInternalIDByPersonalIDResult>
                    <Response xmlns="">
                        <Timestamp date="24/10/2013" time="04:27:37" />
                        <User>
                           <UserInternalID>4907</UserInternalID>
                        </User>
                    </Response>
                </GetUserInternalIDByPersonalIDResult>
           </GetUserInternalIDByPersonalIDResponse>
       </soap:Body>
  </soap:Envelope>
RESPONSE;

$restore = libxml_use_internal_errors(TRUE);
$xml     = simplexml_load_string($response);
libxml_use_internal_errors($restore);

echo $xml->xpath('//Response/User/UserInternalID')[0];

Output:

4907

Online Demo: https://eval.in/57149

0
votes
$doc = new DOMDocument();
libxml_use_internal_errors(true);
$doc->loadHTML($response);
libxml_clear_errors();
$xml = $doc->saveXML($doc->documentElement);
$xml = simplexml_load_string($xml);

Use this helped me in a big way.