1

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.

2
  • I also tried with $xml = simplexml_load_string(trim($response)), but same output. Commented Feb 25, 2018 at 16:39
  • 3
    It's not empty, just SimpleXMLElement doesn't play nice with print_r() or var_dump(). For example, var_dump($xml->getNamespaces()); returns the namespace correctly. Commented Feb 25, 2018 at 16:46

3 Answers 3

7

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
                (
                    ...
                )

        )

)
Sign up to request clarification or add additional context in comments.

Comments

0

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.

Comments

0

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;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.