Parsing XML With Namespaces with SimpleXML

There’s one thing SimpleXML for PHP is horrible to use for: parsing XML containing namespaces. Namespaces requires special handling, and the only way I’ve found that allows you to refer to an element in another namespace, is to use the ->children() method with the namespace. I’m sure there’s an easier way than this, and if you know of any, please leave a comment!

Let’s start with the following XML snippet (using SOAP as an example):


    
        
            asdasd
        
    

The easiest way to do this is to “ignore” the namespaces, and simply do $root->{soap:Envelope} that to access the property. This will not work, as SimpleXML is quite peculiar about it’s namespaces (.. while everything else is simple and easy to use).

One solution is to provide the namespace you’re interested in to the $element->children() method, which returns all the children of the element in a particular namespace (or without arguments, outside any namespace):

$sxml = new SimpleXMLElement(file_get_contents('soap.xml'));

foreach($sxml->children('http://www.w3.org/2001/12/soap-envelope') as $el)
{
    if ($el->getName() == 'Body')
    {
        /* ... */
    }
}

Yes. That’s quite horrible.

But luckily the xpath method can help us:

$elements = $sxml->xpath('//soap:Envelope/soap:Body/queryInstantStreamResponse');

This will actually fetch all the elements titled “queryInstantStreamResponse” which are childs of soap:Envelope and soap:Body. And this works as you expect it to, without having to use children, provide the actual namespace URI, etc.

The xpath method returns an array containing all the matching elements, so in this case you’ll receive an array with a single element, containing the text inside the queryInstantStreamResponse element.

There should be an easier way than this.

3 thoughts on “Parsing XML With Namespaces with SimpleXML”

  1. to throw more hair loss into the mix… add a different namespace to queryInstantStreamResponse and see if you can ever get access to anything in your soap response….

  2. Thanks so much! I was tearing my hair out over a problem like this for ages (metaphorically speaking as I don’t have much left to tear… :-)). I had a soap response with multiple namespaces and needed a solution starting like this:

    $rs_body = $rs_xml->children(‘http://schemas.xmlsoap.org/soap/envelope/’);
    $rs_msg_cnt = $rs_body->Body->children(‘http://axis.frontend.hydra.hotelbeds.com’);

    Thanks!

Leave a Reply

Your email address will not be published.