2010-12-01 6 views
2

У меня есть массив в следующем формате:Преобразование PHP массив JSON дерево

array(
    array('id' => 1, 'parent_id' => null, 'name' => 'lorem ipsum'), 
    array('id' => 2, 'parent_id' => 1, 'name' => 'lorem ipsum1'), 
    array('id' => 3, 'parent_id' => 1, 'name' => 'lorem ipsum2'), 
    array('id' => 4, 'parent_id' => 2, 'name' => 'lorem ipsum3'), 
    array('id' => 5, 'parent_id' => 3, 'name' => 'lorem ipsum4'), 
    array('id' => 6, 'parent_id' => null, 'name' => 'lorem ipsum5'), 
); 

я должен преобразовать этот массив в объект JSON с этим стилем:

var json = { 
    id: "1", 
    name: "loreim ipsum", 
    data: {}, 
    children: [{ 
     id: "2", 
     name: "lorem ipsum1", 
     data: {}, 
     children: [{ 
      id: "3", 
      name: "lorem ipsum2", 
      data: {}, 
      children: [{ 
      .............. 

Как я могу это сделать ? Благодарю.

+0

I не понимайте, как должны выглядеть ваши окончательные данные. В ваших образцовых данных оба элемента 1 и 6 не имеют родителя, но ваш образец вывода сконструирован так, чтобы иметь только один корневой элемент. – 2010-12-01 20:35:10

+0

JSON может иметь несколько корневых элементов, результатом является просто пример. – cnkt 2010-12-01 20:37:08

ответ

10

Мое решение:

$data = array(
    array('id' => 1, 'parent_id' => null, 'name' => 'lorem ipsum'), 
    array('id' => 2, 'parent_id' => 1, 'name' => 'lorem ipsum1'), 
    array('id' => 3, 'parent_id' => 1, 'name' => 'lorem ipsum2'), 
    array('id' => 4, 'parent_id' => 2, 'name' => 'lorem ipsum3'), 
    array('id' => 5, 'parent_id' => 3, 'name' => 'lorem ipsum4'), 
    array('id' => 6, 'parent_id' => null, 'name' => 'lorem ipsum5'), 
); 

$itemsByReference = array(); 

// Build array of item references: 
foreach($data as $key => &$item) { 
    $itemsByReference[$item['id']] = &$item; 
    // Children array: 
    $itemsByReference[$item['id']]['children'] = array(); 
    // Empty data class (so that json_encode adds "data: {}") 
    $itemsByReference[$item['id']]['data'] = new StdClass(); 
} 

// Set items as children of the relevant parent item. 
foreach($data as $key => &$item) 
    if($item['parent_id'] && isset($itemsByReference[$item['parent_id']])) 
     $itemsByReference [$item['parent_id']]['children'][] = &$item; 

// Remove items that were added to parents elsewhere: 
foreach($data as $key => &$item) { 
    if($item['parent_id'] && isset($itemsByReference[$item['parent_id']])) 
     unset($data[$key]); 
} 

// Encode: 
$json = json_encode($data); 
4

Вот код, чтобы сделать то, что вам нужно. Это не нужно элементов, которые должны быть в порядке родительских-потомков в массиве, но будут быстрее завершены, если они есть.

Пожалуйста, изучите комментарии, чтобы понять, что делает код и почему; и если у вас все еще есть вопросы, спросите их тоже!

// Assume your array is $data 

$root = new stdClass; // this is your root item 
$objectMap = array(); // this holds objects indexed by their id 

// Since we need to iterate over the array, but there may be no guarantee 
// that an item's parent will be always encountered before the item itself, 
// we loop as many times as needed, skipping items whose parent we have not 
// yet seen. Hopefully we will see it later and be able to process these 
// items in the next iteration. 
while (!empty($data)) { 

    // Remember how many items there are when starting the loop 
    $count = count($data); 

    // Do the actual work! 
    foreach ($data as $key => $row) { 
     $parentId = $row['parent_id']; 

     if ($parentId === null) { 
      // We just met the root element 
      $current = $root; 
     } 
     else if (isset($objectMap[$parentId])) { 
      // We met an element with a parent that we have already seen 
      $current = new stdClass; 
     } 
     else { 
      // We met an element with an unknown parent; ignore it for now 
      continue; 
     } 

     // Put the current element on the map so that its children will 
     // be able to find it when we meet them 
     $objectMap[$row['id']] = $current; 

     // Add the item to its parent's children array 
     $objectMap[$parentId]->children[] = $current; 

     // Set the item's properties 
     $current->id = $row['id']; 
     $current->name = $row['name']; 
     $current->data = new stdClass; // always empty 
     $current->children = array(); 

     // We successfully processed this, remove it (see why below!) 
     unset($data[$key]); 
    } 

    // OK, we looped over the array once. If the number of items has 
    // not been reduced at all, it means that the array contains only 
    // items whose parents do not exist. Instead of looping forever, 
    // let's just take what we are given and stop here. 
    if ($count == count($data)) { 
     break; 
    } 

    // If there are still items in $data, we will now iterate again 
    // in the hope of being able to process them in the next iteration 
} 

// All set! If $data is not empty now, it means there were items 
// with invalid parent_ids to begin with. 
$output = json_encode($root); 
3

Мое мнение (я знаю ответ был принят, но я работал над этим, так что я буду пост ID = P)

// Test data 
$data = array(
    array('id' => 1, 'parent_id' => null, 'name' => 'lorem ipsum'), 
    array('id' => 2, 'parent_id' => 1, 'name' => 'lorem ipsum1'), 
    array('id' => 3, 'parent_id' => 1, 'name' => 'lorem ipsum2'), 
    array('id' => 4, 'parent_id' => 2, 'name' => 'lorem ipsum3'), 
    array('id' => 5, 'parent_id' => 3, 'name' => 'lorem ipsum4'), 
    array('id' => 6, 'parent_id' => null, 'name' => 'lorem ipsum5'), 
); 

// Randomize, because the data may not be in a top-down order 
shuffle($data); 

// Parse and inspect the result 
$builder = new TreeBuilder($data); 
echo '<pre>', print_r($builder->getTree()), '</pre>'; 


class TreeBuilder 
{ 
    protected $leafIndex = array(); 
    protected $tree  = array(); 
    protected $stack; 

    function __construct($data) 
    { 
    $this->stack = $data; 

    while(count($this->stack)) 
    { 
     $this->branchify(array_shift($this->stack)); 
    } 
    } 

    protected function branchify(&$leaf) 
    { 
    // Root-level leaf? 
    if (null === $leaf['parent_id']) 
    { 
     $this->addLeaf($this->tree, $leaf); 
    } 
    // Have we found this leaf's parent yet? 
    else if (isset($this->leafIndex[$leaf['parent_id']])) 
    { 
     $this->addLeaf($this->leafIndex[$leaf['parent_id']]['children'], $leaf); 
    } else { 
     // Nope, put it back on the stack 
     $this->stack[] = $leaf; 
    } 
    } 

    protected function addLeaf(&$branch, $leaf) 
    { 
    // Add the leaf to the branch 
    $branch[] = array(
     'id'  => $leaf['id'] 
     , 'name'  => $leaf['name'] 
     , 'data'  => new stdClass 
     , 'children' => array() 
    ); 

    // Store a reference so we can do an O(1) lookup later 
    $this->leafIndex[$leaf['id']] = &$branch[count($branch)-1]; 
    } 

    protected function addChild($branch, $leaf) 
    { 
    $this->leafIndex[$leaf['id']] &= $branch['children'][] = $leaf; 
    } 

    public function getTree() 
    { 
    return $this->tree; 
    } 
} 
Смежные вопросы