Kishor Patidar
Kishor Patidar

Reputation: 733

simplexml_load_string() returning a empty object

I am facing an issue with simplexml_load_string function, this function was working before but today it stopped working.

Here is a sample of input xml :-

$response = '<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.beautyfort.com/api/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><SOAP-ENV:Body><ns1:ProductSearchResponse><ns1:TestMode>false</ns1:TestMode><ns1:Page>1</ns1:Page><ns1:ResultsPerPage>1</ns1:ResultsPerPage><ns1:TotalResults>1276</ns1:TotalResults><ns1:Items><ns1:Item><ns1:StockCode>L3720</ns1:StockCode><ns1:Name>David Beckham Instinct Gift Set 30ml EDT + 150ml Shower Gel</ns1:Name><ns1:QuantityAvailable>1</ns1:QuantityAvailable><ns1:UnitPrice Currency="GBP"><ns1:Amount>8.72</ns1:Amount></ns1:UnitPrice><ns1:YourRating xsi:nil="true"/><ns1:YourStockCode></ns1:YourStockCode><ns1:ImageLastUpdated>2016-12-22 18:13:08</ns1:ImageLastUpdated><ns1:ThumbnailImageUrl>https://www.beautyfort.com/pic/Y0NqeTBJbmdvaUx6ZUFOa0MyTlNObmhGckltYnVQQmg%3D</ns1:ThumbnailImageUrl><ns1:HighResImageUrl xsi:nil="true"/></ns1:Item></ns1:Items></ns1:ProductSearchResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>';
$xml = simplexml_load_string(($response));

//This returning following response:-

SimpleXMLElement Object   (
)

Can someone please have an look into this and let me know what is going wrong here.

Upvotes: 1

Views: 5031

Answers (3)

ganzpopp
ganzpopp

Reputation: 594

To answer your question, let's first examine the problem.

Problem

Assuming you are displaying the contents of your $xml variable through:

php > print_r($xml);

Here, you are listing the children of the current node (the root node) with the default namespace (without prefix) which is not declared in that node:

 <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.beautyfort.com/api/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

If you would list the namespaces of that node:

php > print_r($xml->getNamespaces());
Array
(
    [SOAP-ENV] => http://schemas.xmlsoap.org/soap/envelope/
)

there is only a single one visible, because that is the only one actually used in that (root) node excluding its children.

To list all used namespaces of the root and all its children add 'true' as first argument:

php > print_r($xml->getNamespaces(true));
Array
(
    [SOAP-ENV] => http://schemas.xmlsoap.org/soap/envelope/
    [ns1] => http://www.beautyfort.com/api/
    [xsi] => http://www.w3.org/2001/XMLSchema-instance
)

To list all declared namespaces of the root and all its children:

php > print_r($xml->getDocNamespaces(true));
Array
(
    [SOAP-ENV] => http://schemas.xmlsoap.org/soap/envelope/
    [ns1] => http://www.beautyfort.com/api/
    [xsi] => http://www.w3.org/2001/XMLSchema-instance
)

Solution #1

simplexml_load_string allows to set a default namespace as argument, e.g. SOAP-ENV (with extra argument to indicate that it is a prefix):

php > $xml = simplexml_load_string($content, "SimpleXMLElement", 0, "SOAP-ENV", true);

If you now print your variable, you will get closer to what you need:

php > print_r($xml);
SimpleXMLElement Object
(
    [Body] => SimpleXMLElement Object
        (
        )

)

But this only holds for the root node.

When listing children, you still need to specify a namespace if the children use namespaces other than the default (empty) one, and indicate whether its a prefix or namespace:

php > print_r($xml->children("SOAP-ENV", true));
SimpleXMLElement Object
(
    [Body] => SimpleXMLElement Object
        (
        )

)

To see the children of the first root child do the following:

php > print_r($xml->children("SOAP-ENV", true)->children("ns1", true));
SimpleXMLElement Object
(
    [ProductSearchResponse] => SimpleXMLElement Object
        (
            ...
        )

)

But this might not be what you are looking for, as it is not a generic solution.

Solution #2

Use a string replace for all your namespaces and reload the XML document (stored in $content):

php > $content2 = str_replace(array_map(function($e) { return "$e:"; }, array_keys($xml->getDocNamespaces())), array(), $content);

Your input XML now looks like this:

php > echo $content2;
<?xml version="1.0" encoding="UTF-8"?><Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.beautyfort.com/api/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Body><ProductSearchResponse><TestMode>false</TestMode><Page>1</Page><ResultsPerPage>1</ResultsPerPage><TotalResults>1276</TotalResults><Items><Item><StockCode>L3720</StockCode><Name>David Beckham Instinct Gift Set 30ml EDT + 150ml Shower Gel</Name><QuantityAvailable>1</QuantityAvailable><UnitPrice Currency="GBP"><Amount>8.72</Amount></UnitPrice><YourRating nil="true"/><YourStockCode></YourStockCode><ImageLastUpdated>2016-12-22 18:13:08</ImageLastUpdated><ThumbnailImageUrl>https://www.beautyfort.com/pic/Y0NqeTBJbmdvaUx6ZUFOa0MyTlNObmhGckltYnVQQmg%3D</ThumbnailImageUrl><HighResImageUrl nil="true"/></Item></Items></ProductSearchResponse></Body></Envelope>

Reload and print:

php > $xml2 = simplexml_load_string($content2);
php > print_r($xml2);
SimpleXMLElement Object
(
    [Body] => SimpleXMLElement Object
        (
            [ProductSearchResponse] => SimpleXMLElement Object
                (
                    ...
                )

        )

)

Upvotes: 7

Kishor Patidar
Kishor Patidar

Reputation: 733

I tried following to list all products from the XML

 $response = '<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.beautyfort.com/api/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><SOAP-ENV:Body><ns1:ProductSearchResponse><ns1:TestMode>false</ns1:TestMode><ns1:Page>1</ns1:Page><ns1:ResultsPerPage>1</ns1:ResultsPerPage><ns1:TotalResults>1276</ns1:TotalResults><ns1:Items><ns1:Item><ns1:StockCode>L3720</ns1:StockCode><ns1:Name>David Beckham Instinct Gift Set 30ml EDT + 150ml Shower Gel</ns1:Name><ns1:QuantityAvailable>1</ns1:QuantityAvailable><ns1:UnitPrice Currency="GBP"><ns1:Amount>8.72</ns1:Amount></ns1:UnitPrice><ns1:YourRating xsi:nil="true"/><ns1:YourStockCode></ns1:YourStockCode><ns1:ImageLastUpdated>2016-12-22 18:13:08</ns1:ImageLastUpdated><ns1:ThumbnailImageUrl>https://www.beautyfort.com/pic/Y0NqeTBJbmdvaUx6ZUFOa0MyTlNObmhGckltYnVQQmg%3D</ns1:ThumbnailImageUrl><ns1:HighResImageUrl xsi:nil="true"/></ns1:Item></ns1:Items></ns1:ProductSearchResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>';

   $xml = simplexml_load_string(($response));
   $posts = $xml->children('SOAP-ENV', true)->Body->children('ns1', true)->ProductSearchResponse;

Upvotes: 0

Nigel Ren
Nigel Ren

Reputation: 57121

The output your getting is just not helpful more than incorrect. When dealing with SimpleXML and DOMDocument, there structure is quite complex and you don't always get all the information.

When using SimpleXML - the best way of seeing the content of a node is to use asXML(), which recreates the original XML of the node.

$xml = simplexml_load_string($response);

echo $xml->asXML();

This give you your original content.

Upvotes: 0

Related Questions