PHP convert XML to JSON group when there is one child

The article you’ve linked is pretty outdated. For example Services_JSON is normally not needed any longer.

The stable PHP 5.4 version right now has json_encode() function and the JsonSerializable interface as well as iterator_to_array. Even if you’re using the older PHP 5.3 version, the following example is pretty easy to adopt.

So what you actually need is your own JSON encoding of a SimpleXMLElement.

So first of all, let’s just create “our own” Json encoder:

class XML2Json extends SimpleXMLElement
{
}

Wow. That was dead simple. Let’s check that it works:

$converter = new XML2Json($bufferXml);

echo json_encode($converter, JSON_PRETTY_PRINT), "\n";

And the result is already similiar to the result with Services_JSON:

{
    "status": "OK",
    "users": {
        "user": [
            {
                "userName": "johndoe"
            },
            {
                "userName": "johndoe1",
                "fullName": "John Doe"
            },
            {
                "userName": "johndoe2"
            },
            {
                "userName": "johndoe3",
                "fullName": "John Doe Mother"
            },
            {
                "userName": "johndoe4"
            }
        ]
    }
}

But this is not fitting. As the output shows, the searchResult property is missing and also the users are not in a single array like you want them.

So the json_encode needs to be user-defined. To do this in PHP, PHP has the JsonSerializable interface. It consists of a single method named jsonSerialize() and we will make it return a different value now if the name is searchResult to offer both it’s name as property and the users as a flat array. Let’s extend and implement the interface:

class XML2JsonSearchResult extends XML2Json implements JsonSerializable
{

    public function jsonSerialize()
    {
        $name = $this->getName();

        if ($name !== 'searchResult') {
            return $this;
        }

        $value          = (array)$this;
        $value['users'] = iterator_to_array($value['users']->user, FALSE);

        return [$name => $value];
    }
}

All elements that don’t have the name searchResult will get their default JSON encoding by returning $this.

The searchResult will be named and it’s users are flattened by the iterator_to_array() function.

And that is all you need to do. Again the usage-example, it works exactly the same, only this time the class-name differs:

$converter = new XML2JsonSearchResult($bufferXml);

echo json_encode($converter, JSON_PRETTY_PRINT);

And the output now is like you want it:

{
    "searchResult": {
        "status": "OK",
        "users": [
            {
                "userName": "johndoe"
            },
            {
                "userName": "johndoe1",
                "fullName": "John Doe"
            },
            {
                "userName": "johndoe2"
            },
            {
                "userName": "johndoe3",
                "fullName": "John Doe Mother"
            },
            {
                "userName": "johndoe4"
            }
        ]
    }
}

Hope this gives you a good example how to do it nowadays.

The whole code-example at a glance (Online Demo):

class XML2JsonSearchResult extends SimpleXMLElement implements JsonSerializable
{

    public function jsonSerialize()
    {
        $name = $this->getName();

        if ($name !== 'searchResult') {
            return $this;
        }

        $value          = (array)$this;
        $value['users'] = iterator_to_array($value['users']->user, FALSE);

        return [$name => $value];
    }
}

$converter = new XML2JsonSearchResult($bufferXml);

echo json_encode($converter, JSON_PRETTY_PRINT);

Leave a Comment