@krekerov
Fullstack ninja

Как получить JSON tree?

Есть табличка mysql
id pid name
1 0 Группа1
2 1 Группа1.1
3 0 Группа2
4 2 Группа1.1.1
5 1 Группа1.2

как можно вывести массив, чтобы используя функцию json_encode() получался не плоский JSON типа такого [{"id":1,"pid":null,"name":"ipsum"},{"id":2,"pid":1,"name":"ipsum1"},{"id":3,"pid":1,"name":"ipsum2"},{"id":4,"pid":2,"name":"ipsum3"},{"id":5,"pid":3,"name":"ipsum4"},{"id":6,"pid":null,"name":"ipsum5"}]

массив такой $data = array(
array('id' => 1, 'pid' => null, 'name' => 'ipsum'),
array('id' => 2, 'pid' => 1, 'name' => 'ipsum1'),
array('id' => 3, 'pid' => 1, 'name' => 'ipsum2'),
array('id' => 4, 'pid' => 2, 'name' => 'ipsum3'),
array('id' => 5, 'pid' => 3, 'name' => 'ipsum4'),
array('id' => 6, 'pid' => null, 'name' => 'ipsum5')
);

вот тут чувак использует функцию json_encode и у него нормальный json выходит

Как получить итоговый вариант JSON такой
{
        label: 'node1',
        children: [
            { label: 'child1' },
            { label: 'child2' }
        ]
    },
    {
        label: 'node2',
        children: [
            { label: 'child3' }
        ]
    }
  • Вопрос задан
  • 4924 просмотра
Пригласить эксперта
Ответы на вопрос 6
@Next_Alex
Проблема не в json_encode, а в запросе к базе. В результате выполнения запрооса к базе ты получаешь плоский массив, который конечно же преобразуется в плоский json. Добейся сначала получения массива правильной структуры, а потом уже конвертируй.
Ответ написан
Комментировать
rafuck
@rafuck
Вот, собственно, код. Узлы в плоской таблице должны быть отсортированы в порядке ЛВП обхода (а не как у вас, в ширину - см. пример). Если сортировка в ширину критична, то алгоритм будет другой.
function flat2tree(&$flat){
    $tree = array();
    $path = array();
    $pathLength = 0;
    
    $N = (is_array($flat)) ? count($flat) : 0;

    for ($i=0; $i<$N; ++$i){
        $node =& $flat[$i];
        for(; $pathLength && $path[$pathLength-1]['id'] != $node['pid']; --$pathLength);

        if ($pathLength){
            $parent =& $path[$pathLength-1];
            if (!isset($parent['child']) || !is_array($parent['child'])){
                $parent['child'] = array();
            }
            $parent['child'][] = $node;
            $path[$pathLength++] =& $parent['child'][count($parent['child']) - 1];
        }
        else{
            $tree[] = $node;
            $path[$pathLength++] =& $tree[count($tree) - 1];
        }
    }

    return $tree;
}

$flat = array(
    array('id' => 1, 'pid' => null, 'name' => 'ipsum'),
    array('id' => 2, 'pid' => 1, 'name' => 'ipsum1'),
    array('id' => 4, 'pid' => 2, 'name' => 'ipsum3'),
    array('id' => 3, 'pid' => 1, 'name' => 'ipsum2'),
    array('id' => 5, 'pid' => 3, 'name' => 'ipsum4'),
    array('id' => 6, 'pid' => null, 'name' => 'ipsum5')
);
$tree = flat2tree($flat);
var_dump($tree);
echo json_encode($tree);
Ответ написан
Комментировать
akashtrih
@akashtrih
В качестве опции json_encode надо передать константу JSON_PRETTY_PRINT, которая доступна с версии PHP 5.4 (пример)
br1.php.net/manual/ru/json.constants.php#constant....
Ответ написан
alexiusp
@alexiusp
senior frontend developer
Согласен с предыдущим ответом. json_encode/json_decode не меняют структуру данных. Так что нужно написать функцию php (или в БД), которая будет выдавать соответствующим образом структурированный результат.
В примере, указанном тобой, как раз в качестве ответа предлагают подобную функцию. Лично мне тот ответ не нравится, т.к. там прямо в коде прошита структура данных с ключами. Стоит формату чуть-чуть поменяться - всё полетит, придётся всю функцию переписывать - это не очень хороший подход.
Твоя структура в этом плане попроще - обычное дерево. Если никто раньше не ответит, попробую вечерком набросать рекурсивную функцию для обхода этого дерева. Уже раз десять подобные функции писал. В том числе и когда в вузе учился. ;)
Ответ написан
Комментировать
rafuck
@rafuck
Еще вариант, менее "классический" что ли.. Побольше памяти будет есть, но не зависит от сортировки.
function flat2tree(&$flat){
    $tree = array();
    $nodeMap = array();
    
    $N = (is_array($flat)) ? count($flat) : 0;

    for ($i=0; $i<$N; ++$i){
        $node =& $flat[$i];
        
        if (isset($nodeMap[$node['pid']])){
            $parent =& $nodeMap[$node['pid']];
            if (!isset($parent['child']) || !is_array($parent['child'])){
                $parent['child'] = array();
            }
            $parent['child'][] = $node;
            $nodeMap[$node['id']] =& $parent['child'][count($parent['child']) - 1];
        }
        else{
            $tree[] = $node;
            $nodeMap[$node['id']] =& $tree[count($tree) - 1];
        }
    }

    return $tree;
}

$flat = array(
    array('id' => 1, 'pid' => null, 'name' => 'ipsum'),
    array('id' => 2, 'pid' => 1, 'name' => 'ipsum1'),
    array('id' => 3, 'pid' => 1, 'name' => 'ipsum2'),
    array('id' => 4, 'pid' => 2, 'name' => 'ipsum3'),
    array('id' => 5, 'pid' => 3, 'name' => 'ipsum4'),
    array('id' => 6, 'pid' => null, 'name' => 'ipsum5')
);
$tree = flat2tree($flat);
var_dump($tree);
echo json_encode($tree);
Ответ написан
Комментировать
@Artso
перед var_dump($array); запишите echo '<pre>';
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы