Home > OS >  simplexml_load_string always fails if there are special characters inside tags
simplexml_load_string always fails if there are special characters inside tags

Time:07-22

I'm receiving from an external web service an XML like this(notice the colons inside the tags)

XML

<?xml version='1.0' encoding='UTF-8'?>
<env:Envelope
    xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:ns0="http://webservice/CrsWSApi.wsdl/types/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <env:Body>
        <ns0:callwsapiResponseElement>
            <ns0:result>
                <ns0:object>BTS</ns0:object>
                <ns0:receiver>BTSV45_ANSF_PROD-AKITT</ns0:receiver>
                <ns0:sender>ANSFP</ns0:sender>
                <ns0:data>
                {"name":"Paolo", "cognome": Rossi, "data":"18/11/1983"}
                </ns0:data>
                <ns0:errormess xsi:nil="true"/>
                <ns0:errorcode xsi:nil="true"/>
                <ns0:status>1</ns0:status>
                <ns0:sessionid>akit1</ns0:sessionid>
            </ns0:result>
        </ns0:callwsapiResponseElement>
    </env:Body>
</env:Envelope>

if I use this function to parse it

PHP

$xml = simplexml_load_string($xml) or die("Error: Cannot create object");

I'm always receiving Error. If I remove the colons it works as expected. Is there a way to make this works without manipulating the colons before the xml parsing?

I want to avoid this manipulation PHP

$xml = preg_replace(['/env:/','/:env(?!=)/','/ns0:/','/:ns0(?!=)/'], '', $myXMLData);

UPDATE

I already accepted a good answer that is reporting usefull links on how namespases are working in an xml environment, but I want to share another way to obtain the same result without parsing an xpath expression. We can you use the children method of simple_xml_loadstring specifiying the second parameter as a namespace.

fot the above code you can obtain the ns0:data content with this code(before you have to change the if statement as the accepted answer)

PHP

    $xml = simplexml_load_string($response);
    
    echo $xml
         ->children("env", true)
         ->Body
         ->children("ns0", true)
         ->callwsapiResponseElement
         ->result
         ->data;

// This will print
{"name":"Paolo", "cognome": Rossi, "data":"18/11/1983"}

CodePudding user response:

For me it is very curious the return of simplexml_load_string (https://www.php.net/manual/en/function.simplexml-load-string.php):

This function may return Boolean false, but may also return a non-Boolean value which evaluates to false. Please read the section on Booleans for more information. Use the === operator for testing the return value of this function.

And indeed if you replace the or die:

<?php
$response = <<<XML
<?xml version='1.0' encoding='UTF-8'?>
<env:Envelope
    xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:ns0="http://webservice/CrsWSApi.wsdl/types/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <env:Body>
        <ns0:callwsapiResponseElement>
            <ns0:result>
                <ns0:object>BTS</ns0:object>
                <ns0:receiver>BTSV45_ANSF_PROD-AKITT</ns0:receiver>
                <ns0:sender>ANSFP</ns0:sender>
                <ns0:data>
                {"name":"Paolo", "cognome": Rossi, "data":"18/11/1983"}
                </ns0:data>
                <ns0:errormess xsi:nil="true"/>
                <ns0:errorcode xsi:nil="true"/>
                <ns0:status>1</ns0:status>
                <ns0:sessionid>akit1</ns0:sessionid>
            </ns0:result>
        </ns0:callwsapiResponseElement>
    </env:Body>
</env:Envelope>
XML;
$xml = simplexml_load_string($response);
if($xml===false){
    die();
}
echo $xml->xpath("//*[local-name() = 'receiver']")[0];

Results:

BTSV45_ANSF_PROD-AKITT

You can then use the namespaces to find your data. This is a nice post Reference - How do I handle Namespaces (Tags and Attributes with a Colon in their Name) in SimpleXML?

  • Related