5

I have this array of objects returned by a SQL query where top_id is my parent ID field:

Array (
[0] => stdClass Object ( [id] => 1 [top_id] => 0 [name] => Cat 1 )
[1] => stdClass Object ( [id] => 2 [top_id] => 0 [name] => Cat 2 ) 
[2] => stdClass Object ( [id] => 3 [top_id] => 0 [name] => Cat 3 ) 
[3] => stdClass Object ( [id] => 4 [top_id] => 2 [name] => Subcat 1 ) 
[4] => stdClass Object ( [id] => 5 [top_id] => 2 [name] => Subcat 2 ) 
[5] => stdClass Object ( [id] => 6 [top_id] => 3 [name] => Subcat 3 ) 
[6] => stdClass Object ( [id] => 7 [top_id] => 5 [name] => Subcat 4 )
)

Now I need to obtain a nested list like this using PHP:

<ul>
  <li>Cat 1</li>
  <li>Cat 2
    <ul>
      <li>Subcat 1</li>
      <li>Subcat 2
        <ul>
          <il>Subcat 3
            <ul>
              <li>Subcat 4</li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
  <li>Cat 3</li>
</ul>

Any idea? Thanks

1
  • Does "top_id" indicate which category a sub-category belongs to? Commented Nov 5, 2011 at 15:49

1 Answer 1

10

First of all map the objects onto a new hash (array) in which the index is the id:

// map the array onto hash
$hash = array();
foreach($array as $object)
{
    $hash[$object->id] = array('object' => $object);
}

Then transpose this flat hash into a tree-like structure, see this answer for another code example, it's merely the same here:

// build tree from hash
$tree = array();
foreach($hash as $id => &$node)
{
    if ($parent = $node['object']->top_id)
        $hash[$parent]['children'][] =& $node;
    else
        $tree[] =& $node;
}
unset($node, $hash);

Finally you can output this tree-like structure as HTML. This can be done with either a stack or recursive. This is one variant with recursion:

// render tree
function render_tree($tree)
{
    echo '<ul>', "\n";
    foreach($tree as $node)
    {
        render_node($node);
    }
    echo '</ul>';
}

// render tree node
function render_node($node, $level = 0)
{
    $inset = str_repeat('    ', $level) . '  ';
    echo $inset, '<li>', $node['object']->name;
    if (isset($node['children']))
    {
        echo "\n", $inset, '  <ul>', "\n";
        foreach($node['children'] as $node)
        {
            render_node($node, $level+1);
        }
        echo $inset, '  </ul>', "\n", $inset;
    }
    echo '</li>', "\n";
}

// output
render_tree($tree);

Output:

<ul>
  <li>Cat 1</li>
  <li>Cat 2
    <ul>
      <li>Subcat 1</li>
      <li>Subcat 2
        <ul>
          <li>Subcat 4</li>
        </ul>
      </li>
    </ul>
  </li>
  <li>Cat 3
    <ul>
      <li>Subcat 3</li>
    </ul>
  </li>
</ul>

Full code Example + HTML Demo.

Sign up to request clarification or add additional context in comments.

1 Comment

The full code example Link is broken

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.