Search code examples
phparraysjsonxmlsimplexml

PHP Converting from XML to JSON with a SimpleXML object. Array with <items> tag causing issues


We are using SimpleXML to try and convert XML to JSON, and in turn convert to a PHP object, so that we can compare out Soap API with our Rest API. We have a request that returns quite a lot of data, but the part in question is where we have a nested array.

The array is returned with the tag in XML, however we do not want this translated into the JSON.

The XML that we get is as follows:

                  <apns>
                     <item>
                        <apn>apn</apn>
                     </item>
                  </apns>

So when it is translated into JSON it looks like this:

{"apns":{"item":{"apn":"apn"}}

In reality, we want SimpleXML to convert to the same JSON as in our Rest API, which looks like the following:

{"apns":[{"apn":"apn"}]}

The array could contain more than one thing, for example:

                  <apns>
                     <item>
                        <apn>apn</apn>
                     </item>
                     <item>
                        <apn>apn2</apn>
                     </item>
                  </apns>

Which I'm assuming will just error in JSON or have the first one overwritten.

I'd expect SimpleXML to be able to handle this natively, but if not has anyone got a fix that doesn't involve janky string manipulation?

TIA :)


Solution

  • A generic conversion has no possibility to know that a single element should be an array in JSON.

    SimpleXMLElement properties can be treated as an Iterable to traverse sibling with the same name. They can be treated as an list or a single value.

    This allows you to build up your own array/object structure and serialize it to JSON.

    $xml = <<<'XML'
    <apns>
      <item>
        <apn>apn1</apn>
      </item>
      <item>
        <apn>apn2</apn>
      </item>
    </apns>
    XML;
    
    $apns = new SimpleXMLElement($xml);
    
    $json = [
        'apns' => []
    ];
    foreach ($apns->item as $item) {
        $json['apns'][] = ['apn' => (string)$item->apn]; 
    }
    
    echo json_encode($json, JSON_PRETTY_PRINT);
    

    This still allows you to read/convert parts in a general way. Take a more in deep look at the SimpleXMLElement class. Here are method to iterate over all children or to get the name of the current node.