Skip to content
Advertisement

Convert flat JSON to nested JSON with PHP

I have a JSON file with a single array and all elements in the same level. Each of the entries has a “level” attribute between 1 and 4. I want to have a nested array in the end which has all level 4 inside the level 3, all level 3 inside the level 2, all level 2 inside the level 1.

The JSON example is like this:

[{“text e”:”Test”,”id”:1073,”level”:1,”chapter”:”1″}, {“text e”:”Test 2″,”id”:1073,”level”:2,”chapter”:”1.1″}, {“text e”:”Test 3″,”id”:1063,”level”:2,”chapter”:”1.2″}, {“text e”:”Test 4″,”id”:1031,”level”:3,”chapter”:”1.2.1″}, {“text e”:”Test 5″,”id”:1334,”level”:4,”chapter”:”1.2.1.1″}, {“text e”:”Test 6″,”id”:1127,”level”:2,”chapter”:”1.3″}, {“text e”:”Test 7″,”id”:1092,”level”:2,”chapter”:”1.4″}, {“text e”:”Test 8″,”id”:1012,”level”:1,”chapter”:”2″}]

<?php
$json = json_decode(file_get_contents("menuitems.json"), true);
$newArr = array();
$keyLevel1 = 0;
$keyLevel2 = 0;
$keyLevel3 = 0;
$keyLevel4 = 0;
foreach ($json as $key => $item) {
    if ($item['level'] == 1) {
        $newArr[$keyLevel1] = $item;
        $keyLevel1 = $keyLevel1 + 1;
        $keyLevel2 = 0;
        $keyLevel3 = 0;
        $keyLevel4 = 0;
    } else if ($item['level'] == 2) {
        $newArr[$keyLevel1][$keyLevel2] = $item;
        $keyLevel2 = $keyLevel2 + 1;
        $keyLevel3 = 0;
        $keyLevel4 = 0;
    } else if ($item['level'] == 3) {
        $newArr[$keyLevel1][$keyLevel2][$keyLevel3] = $item;
        $keyLevel3 = $keyLevel3 + 1;
        $keyLevel4 = 0;
    } else if ($item['level'] == 4) {
        $newArr[$keyLevel1][$keyLevel2][$keyLevel3][$keyLevel4] = $item;
        $keyLevel4 = $keyLevel4 + 1;
    }
}
echo json_encode($newArr);
?>

This code seems to work for the first level but the level 2 of the last item are written in the last object and they’re not nesting. What am I doing wrong?

Advertisement

Answer

This is a classic off-by-one error. You’re incrementing all of the keyLevel variables at the wrong time. The simplest fix might be to always (re-)initialize them all to -1, and then increment before using, for instance, the first “if” would become:

$keyLevel1 = -1;
...

    if ($item['level'] == 1) {
        $keyLevel1 = $keyLevel1 + 1;
        $newArr[$keyLevel1] = $item;
        $keyLevel2 = -1;
        $keyLevel3 = -1;
        $keyLevel4 = -1;
    }

That way, $keyLevel1 will have the correct value when you process the subsequent level 2, 3, and 4 items.

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement