Peter J. Nicholls Peter J. Nicholls - 1 month ago 10
PHP Question

SimpleXML element object blank

I get an XML response from remote service. I call

echo htmlentities($xml);
and get the XML as formatted beneath.

However, if I want it as an SimpleXML array, I get this output (trimmed):

Array
(
[response] =>
[result] =>
[msg] => Command completed successfully
[resData] =>
[trID] =>
[clTRID] => 75d5f6b852e509abd44395ae3caa3b65
[svTRID] => live-5808720e-101816-1
)


How do I access the object?

Returned XML:

<?xml version="1.0" encoding="utf-8"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<response>
<result code="1000">
<msg>Command completed successfully</msg>
</result>
<resData>
<ext-contact:lstData xmlns:ext-contact="http://www.heartinternet.co.uk/whapi/ext-contact-2.0">
<ext-contact:contact>
<ext-contact:id>3ec46e4d65ff535a</ext-contact:id>
<ext-contact:name>John Smith</ext-contact:name>
<ext-contact:org>domain-name.com</ext-contact:org>
<ext-contact:addr><ext-contact:street>2 Fairways House</ext-contact:street>
<ext-contact:pc>Post Code</ext-contact:pc>
</ext-contact:addr>
<ext-contact:email>email@domain-name.com</ext-contact:email>
</ext-contact:contact>
</ext-contact:lstData>
</resData>
<trID>
<clTRID>75d5f6b852e509abd44395ae3caa3b65</clTRID>
<svTRID>live-5808720e-101498-1</svTRID>
</trID>
</response>
</epp>

Answer

Issue of namespace :)

To get your data, use $x->response->resData->children('http://www.heartinternet.co.uk/whapi/ext-contact-2.0')

$x = simplexml_load_string($xml);

// get the list of namespaces
$ns = $x->getNamespaces(true);
var_dump($ns);
/** RETURN:
 * array (size=2)
 *   '' => string 'urn:ietf:params:xml:ns:epp-1.0' (length=30)
 *   'ext-contact' => string 'http://www.heartinternet.co.uk/whapi/ext-contact-2.0' (length=52)
 **/

var_dump($x);
/** RETURN:
 * only some data, except ext-contract ones
 **/


var_dump($x->response->resData->children($ns['ext-contact']));
/** RETURN:
 * object(SimpleXMLElement)[5]
 *  public 'lstData' => 
 *    object(SimpleXMLElement)[2]
 *      public 'contact' => 
 *        object(SimpleXMLElement)[3]
 *          public 'id' => string '3ec46e4d65ff535a' (length=16)
 *          public 'name' => string 'John Smith' (length=10)
 *          public 'org' => string 'domain-name.com' (length=15)
 *          public 'addr' => 
 *            object(SimpleXMLElement)[6]
 *              ...
 *          public 'email' => string 'email@domain-name.com' (length=21)
 **/

Edit: Add my tips:

/**
 * Function simplexml_unnamespace
 **
 * Unnamespace all xml with namespace provided or all list (by default)
 **
 * @param SimpleXMLElement $xml : SimpleXMLElement to be parsed
 * @param SimpleXMLElement|Array|string|null $ns = null: namespaces to be soft deleted
 * @param boolean $softDeletion = false : Delete completely the namespace or keep _ns attribute
 **
 * @author Olivares Georges <http://olivares-georges.net>
 **
 * Examples:
 *  simplexml_unnamespace($XML, 'name-space');
 *    Will remove 'name-space' namespace values 
 *  simplexml_unnamespace($XML, null, true);
 *    Will remove all namespaces (detected via $XML->getNamespaces(true) and delete them completely
 *  simplexml_unnamespace($XML->subElt, $XML);
 *    Will linearize <subElt /> elements, and use $XML to get the list of namescape (xml root element)
 */
function simplexml_unnamespace(SimpleXMLElement $xml, $ns = null, $softDeletion = false) {

    $new_xml = $xml->asXml();

    if( is_null($ns) && !is_null($xml) ) {
        $ns = $xml->getNamespaces(true);
    }
    else if( $ns instanceof SimpleXMLElement ) {
        $ns = $ns->getNamespaces(true);
    }
    else if( is_string($ns) ) {
        $ns = [$ns => ''];
    }
    else if( is_array($ns) ) {
        // keep array
    }
    else {
        trigger_error('Second parameter of ' . __FUNCTION__ . ' should be null, a string or an array');
    }

    foreach( (array) $ns as $nsKey => $nsValue ) {
        $new_xml = preg_replace(
            '`<' . preg_quote($nsKey) . ':(.[^ >]+)`',
            $softDeletion ? '<$1' : '<$1 _ns="' . $nsKey . '"',
            $new_xml
        );
        $new_xml = str_replace(' xmlns:' . $nsKey . '="' . $nsValue . '"', '', $new_xml);
        $new_xml = str_replace('</' . $nsKey . ':', '</', $new_xml);
    }

    return simplexml_load_string($new_xml);
}

How to use it:

// load XML
$initialXML = simplexml_load_string($xml);

// Unnamespace function
$withoutNsXml = simplexml_unnamespace($initialXML, 'ext-contact', false);

echo '<pre>', htmlspecialchars($withoutNsXml->asXml()), '</pre>';

Result:

<?xml version="1.0" encoding="utf-8"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
    <response>
        <result code="1000">
            <msg>Command completed successfully</msg>
        </result>
        <resData>
            <lstData xmlns:ext-contact="http://www.heartinternet.co.uk/whapi/ext-contact-2.0" _ns="ext-contact">
                <contact _ns="ext-contact">
                    <id _ns="ext-contact">3ec46e4d65ff535a</id>
                    <name _ns="ext-contact">John Smith</name>
                    <org _ns="ext-contact">domain-name.com</org>
                    <addr _ns="ext-contact"><street _ns="ext-contact">2 Fairways House</street>
                        <pc _ns="ext-contact">Post Code</pc>
                    </addr>
                    <email _ns="ext-contact">email@domain-name.com</email>
                </contact>
            </lstData>
        </resData>
        <trID>
            <clTRID>75d5f6b852e509abd44395ae3caa3b65</clTRID>
            <svTRID>live-5808720e-101498-1</svTRID>
        </trID>
    </response>
</epp>

And the data:

object(SimpleXMLElement)[5]
  public 'lstData' => 
    object(SimpleXMLElement)[2]
      public 'contact' => 
        object(SimpleXMLElement)[3]
          public 'id' => string '3ec46e4d65ff535a' (length=16)
          public 'name' => string 'John Smith' (length=10)
          public 'org' => string 'domain-name.com' (length=15)
          public 'addr' => 
            object(SimpleXMLElement)[6]
              ...
          public 'email' => string 'email@domain-name.com' (length=21)