PHP convert XML to JSON group when there is one ch

2019-01-08 02:18发布

问题:

I use this PHP class to convert XML to JSON:http://www.ibm.com/developerworks/library/x-xml2jsonphp/

For example for this XML:

<?xml version="1.0" encoding="UTF-8"?>
<searchResult>
    <status>OK</status>
    <users>
        <user>
            <userName>johndoe</userName>
        </user>
        <user>
            <userName>johndoe1</userName>
            <fullName>John Doe</fullName>
        </user>
        <user>
            <userName>johndoe2</userName>
        </user>
        <user>
            <userName>johndoe3</userName>
            <fullName>John Doe Mother</fullName>
        </user>
        <user>
            <userName>johndoe4</userName>
        </user>
    </users>
</searchResult>

The result is:

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

But i would like:

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

Grouping "user" in "users", because this is an array with just one child.

I've search another class to convert XML to JSON to have this result but i've not find any ressources.

Can you please help me to solve my problem.

Thanks in advance, best regards Fabrice

回答1:

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);