Recursive Multidimensional Array to HTML nested code - php

Im trying to create nested blocks of HTML code from a Multidimensional Array in PHP using a recursive function. However I can not seem to print the tags in a nested order.
Here is the original array:
$array_1 =
array
(
array
(
'id' => '1',
'tag' => 'div1',
'parent' => '0'
),
array
(
'id' => '2',
'tag' => 'div2',
'parent' => '1'
),
array
(
'id' => '3',
'tag' => 'div3',
'parent' => '2'
),
array
(
'id' => '4',
'tag' => 'div4',
'parent' => '2'
),
array
(
'id' => '5',
'tag' => 'div5',
'parent' => '0'
),
array
(
'id' => '6',
'tag' => 'div6',
'parent' => '5'
),
array
(
'id' => '7',
'tag' => 'div7',
'parent' => '0'
)
);
The first thing I do is to use a function to turn this array into a multidimensional array by building a tree structure using the parent element of each record as reference:
function buildTree(array $elements, $parentId = 0) {
$branch = array();
foreach ($elements as $element)
{
if ($element['parent'] == $parentId)
{
$children = buildTree($elements, $element['id']);
if ($children)
{
$element['children'] = $children;
}
$branch[] = $element;
}
}
return $branch;
}
$tree_1 = buildTree($array_1);
Once this is done the multidimensional array should look like this:
Array
(
[0] => Array
(
[id] => 1
[name] => div1
[parent] => 0
[children] => Array
(
[0] => Array
(
[id] => 2
[name] => div2
[parent] => 1
[children] => Array
(
[0] => Array
(
[id] => 3
[name] => div3
[parent] => 2
)
[1] => Array
(
[id] => 4
[name] => div4
[parent] => 2
)
)
)
)
)
[1] => Array
(
[id] => 5
[name] => div5
[parent] => 0
[children] => Array
(
[0] => Array
(
[id] => 6
[name] => div6
[parent] => 5
)
)
)
[2] => Array
(
[id] => 7
[name] => div7
[parent] => 0
)
)
The next thing to do is to output the html elements in a nested order. In this example Im using symbolic tag names such as div1, div2, etc; but in reality they could be any html tags like divs, h1, ul,li, form, etc; with their opening and closing tags.
To accomplish this I use the following recursive function, however my problem is that it does not show the html elements in a nested order as they should be.
function recursive($array, $level = 0)
{
foreach($array as $key => $value)
{
if (!is_array($value) && $key == "tag") { echo str_repeat(" ", $level), "[".$value."]", ''; }
//If $value is an array.
if(is_array($value))
{
//We need to loop through it.
recursive($value, $level + 1);
}
else
{
//It is not an array, so print it out.
if ($key == "tag") { echo "[/".$value."]", '<br>'; }
}
}
}
$tree_2 = recursive($tree_1);
echo $tree_2;
This is how it currently outputs the html tags from the array:
[div1][/div1]
[div2][/div2]
[div3][/div3]
[div4][/div4]
[div5][/div5]
[div6][/div6]
[div7][/div7]
And this is how the html tags should be output in reality based on the multidimensional array's nested order (please note how some div tags contain other div tags before their closing element):
[div1]
[div2]
[div3][/div3]
[div4][/div4]
[/div2]
[/div1]
[div5]
[div6][/div6]
[/div5]
[div7][/div7]
How can I get the html tags printed in the right nested order like in the last example? What am I missing? Thanks so much!

The issue is that the key tag is before children in the $tree_1 array.
Whilst I would personally change your data structure around to make it "easier" to use in the recursive function, you can change your recursive function to make it work like this:
function recursive($array, $level = 0)
{
// Check if we are using an associative array or indexed array
if(isset($array['tag'])) {
echo str_repeat(" ", $level), "[" . $array['tag'] . "]", '';
if(isset($array['children'])) {
echo "<br />";
recursive($array['children'], $level + 1);
echo str_repeat(" ", $level), "[/" . $array['tag'] . "]" , '';
} else {
echo "[/" . $array['tag'] . "]";
}
echo "<br />";
} else {
foreach($array as $key => $value)
{
recursive($value, $level + 1);
}
}
}
Add additional line breaks and formatting where required

A rewrite of your function:
function recursive2($array, &$level, $indentClosingTag = true)
{
$level++;
for($i = 0; $i<count($array); $i++) {
$data = $array[$i];
$indent = str_repeat(' ', $level);
echo $indent . "[".$data['tag'].']';
if (isset($data['children'])) {
echo '<br>';
$level++;
recursive2($data['children'], $level, true);
$level--;
} else {
$indentClosingTag = false;
}
echo ($indentClosingTag ? $indent : ''). "[/".$data['tag'].']'.'<br>';
}
$level--;
}
$l = 0;
recursive2($tree_1, $l);

Related

Create n-level menu array from associative array

I want to create one n-level menu array from my php array. There can be n-level of children. The main array will be same means not a multidimensional n-level array. I've provided a sample array which meets the array structure I'm using.
$menu_array =
Array
(
[menu-main] => Array
(
[menu_name] => Menu Name 1
[menu_slug] => menu-main
[parent_menu_slug] =>
)
[menu-sub-main] => Array
(
[menu_name] => Sub Menu 1
[menu_slug] => menu-sub-main
[parent_menu_slug] => menu-main
)
[menu-sub-sub-main] => Array
(
[menu_name] => Sub Sub Menu 1
[menu_slug] => menu-sub-sub-main
[parent_menu_slug] => menu-sub-main
)
[menu-main1] => Array
(
[menu_name] => Menu Name 1
[menu_slug] => menu-main1
[parent_menu_slug] =>
)
)
I want to create the n-level array to generate the menu from this array. To do so, I tried below
$x = [];
$tmp = array_combine(array_column($menu_array,'menu_slug'), $menu_array);
//parent menus only
foreach ($tmp as $k => $t) {
if (empty($t['parent_menu_slug'])) {
$x[$t['menu_slug']] = $t;
unset($tmp[$k]);
}
}
$d = [];
$rec_fn = function ($temp,$parent_slug = '') use (&$rec_fn,$x,&$d) {
if ($parent_slug && array_key_exists($parent_slug,$x)) {
$d[$parent_slug]['children'][] = $temp;
} else {
foreach ($temp as $c) {
if (!empty($c['parent_menu_slug'])) {
$d['children'][] = $rec_fn($c,$c['parent_menu_slug']);
}
}
}
return $d;
};
$final_menu = $rec_fn($tmp);
But it is not returning the required result. The required result is
Array
(
[menu-main] => Array
(
[menu_name] => Menu Name 1
[menu_slug] => menu-main
[parent_menu_slug] =>
[children] => array(
[menu-sub-main] => Array
(
[menu_name] => Sub Menu 1
[menu_slug] => menu-sub-main
[parent_menu_slug] => menu-main
[children] => array(
[menu-sub-sub-main] => Array
(
[menu_name] => Sub Sub Menu 1
[menu_slug] => menu-sub-sub-main
[parent_menu_slug] => menu-sub-main
)
.
.
)
)
.
.
)
)
[menu-main1] => Array
(
[menu_name] => Menu Name 1
[menu_slug] => menu-main1
[parent_menu_slug] =>
)
..
)
Any help will be appreciated
From link
I have made some function parameters changes as per requirement and to get exact output I changed branch line.
Here is the recursive function to achieve this,
function buildTree(array $elements, $options = [
'parent_id_column_name' => 'parent_menu_slug',
'children_key_name' => 'children',
'id_column_name' => 'menu_slug'], $parentId = '')
{
$branch = array();
foreach ($elements as $element) {
if ($element[$options['parent_id_column_name']] == $parentId) {
// we will call for every node which is having its child using recursion
$children = buildTree($elements, $options, $element[$options['id_column_name']]);
if ($children) { // if it have children array then save it
$element[$options['children_key_name']] = $children;
}
// we will save every node's parent generated recursive data here
$branch[$element['menu_slug']] = $element; // I changed this line
}
}
// recursive generated data returned
return $branch;
}
Here is working demo.

From php multidimensional array trying to create nested ul li menu (unlimited nested levels)

Here is what i have got http://codepad.org/iDoXXsLX
Have array like this
Array
(
[0] => Array
(
[NumberRenamed] => 17
[TopicName] => Products
[UpperLevelNumberRenamed] => 0
)
[17] => Array
(
[0] => Array
(
[1] => Array
(
[NumberRenamed] => 18
[TopicName] => Computers
[UpperLevelNumberRenamed] => 17
)
)
)
[18] => Array
(
[0] => Array
(
[2] => Array
(
[NumberRenamed] => 16
[TopicName] => Laptops
[UpperLevelNumberRenamed] => 18
)
)
)
[16] => Array
(
[0] => Array
(
[4] => Array
(
[NumberRenamed] => 8
[TopicName] => Dell
[UpperLevelNumberRenamed] => 16
)
)
)
)
Top level item is Products, first sub-level item is Computers, next sub-level is Laptops, then again next sub-level Dell
For each sub-level item UpperLevelNumberRenamed == to closest upper level NumberRenamed.
Want to get result like this
Products
Computers
Laptops
Dell
Acer
Desktops
Home
Tried this
foreach( $main_topics as $k_main_topics => $v_main_topics ){
if( isset($v_main_topics['UpperLevelNumberRenamed']) and $v_main_topics['UpperLevelNumberRenamed'] == 0 ){
//print only top level topics
echo $v_main_topics['TopicName']. '<br/>';
}
else{//if not top level topic
foreach( $v_main_topics[0] as $k_v_main_topics_0 => $v_v_main_topics_0 ){
echo $v_v_main_topics_0['TopicName']. '<br/>';
}//foreach( $v_main_topics[0] as $k_v_main_topics_0 => $v_v_main_topics_0 )
}//else{
}//foreach( $main_topics as $k_main_topics => $v_main_topics )
But get this
Products
Home
Computers
Laptops
Desktops
Dell
Acer
Something incorrect, but can not understand what. Please, advice what need to correct/change in the code
Trying another way
Initial array is one dimensional array. Trying to get ul li navigation from one dimensional.
Here is what i did http://codepad.org/OLtxyL4X
Here's a summary of what it does:
flatten the array recursively
build a multi-dimensional relation map
create 1D relationships that link UpperLevelNumberRenamed to NumberRenamed
print out the multi-dimensional as an ul-li list.
Here it is:
$flat = array();
foreach (new RecursiveIteratorIterator(new RecursiveArrayIterator($main_topics)) as $i)
$flat[] = $i;
$final = array();
$defs = array();
for ($i = 0; $i < count($flat); $i += 3)
if ($flat[$i + 2] == 0) {
$final[$flat[$i + 1]] = array();
$defs[$flat[$i]] = &$final[$flat[$i + 1]];
} else {
$defs[$flat[$i + 2]][$flat[$i + 1]] = array();
$defs[$flat[$i]] = &$defs[$flat[$i + 2]][$flat[$i + 1]];
}
function array2ul($array) {
$out = "<ul>";
foreach($array as $key => $elem)
$out = is_array($elem) ?
$out . "<li><span>$key</span>" . array2ul($elem) . "</li>" :
$out = $out."<li><span>$key:[$elem]</span></li>";
$out = $out . "</ul>";
return $out;
}
echo array2ul($final);
Output:
<ul><li><span>Products</span><ul><li><span>Computers</span><ul><li><span>Laptops</span><ul><li><span>Dell</span><ul></ul></li><li><span>Acer</span><ul></ul></li></ul></li><li><span>Desktops</span><ul></ul></li></ul></li></ul></li><li><span>Home</span><ul></ul></li></ul>
This shall be a working example using recursion, not tested though:
Define the array
$main_array = Array
(
'10' => Array
(
'name' => 'Products'
'children' => Array
(
'12' => Array
(
'name' => 'Laptop',
'children' => Array
(
'13' => Array
(
'name' => 'Dell',
),
'14' => Array
(
'name' => 'Acer',
)
)
)
'14' => Array
(
'name' => 'Desktop',
'children' => Array
(
'15' => Array
(
'name' => 'Sony',
),
'16' => Array
(
'name' => 'Apple',
)
)
),
)
)
)
Create and call the function :
function createList($main_topics)
{
if($main_topics == null || sizeof($main_topics) <= 0)
{
return '';
}
$list = '<ul>';
foreach($main_topics as $k_main_topics => $v_main_topics )
{
$list .= '<li id="' . $k_main_topics'"> '. $v_main_topics['name'] . ' ' . createList(isset($v_main_topics["children"]) ? $v_main_topics["children"] : null) . '</li>' ;
}
$list .= '</ul>';
return $list;
}
echo createList($main_array);

php tree ul li hierarchy menu from array

we have this array from mysqli query output :
$items = Array
(
Array
(
'id' => 1,
'title' => 'menu1',
'parent_id' => 0
),
Array
(
'id' => 2,
'title' => 'submenu1-1',
'parent_id' => 1
),
Array
(
'id' => 3,
'title' => 'submenu1-2',
'parent_id' => 1
),
Array
(
'id' => 4,
'title' => 'menu2',
'parent_id' => 0
),
Array
(
'id' => 5,
'title' => 'submenu2-1',
'parent_id' => 4
)
);
and we need this html output with php :
<ul>
<li><a>menu1</a>
<ul>
<li><a>submenu1-1</a></li>
<li><a>submenu1-2</a></li>
</ul>
</li>
<li><a>menu2</a>
<ul>
<li><a>submenu2-1</a></li>
</ul>
</li>
</ul>
can anyone help me ?
Probably this is very easy but I have tried everything already without success !!
finally i found answer like this:
function generateTreeMenu($datas, $parent = 0, $limit=0){
if($limit > 1000) return '';
$tree = '';
$tree = '<ul>';
for($i=0, $ni=count($datas); $i < $ni; $i++){
if($datas[$i]['parent_id'] == $parent){
$tree .= '<li><a>';
$tree .= $datas[$i]['title'].'</a>';
$tree .= generatePageTree($datas, $datas[$i]['id'], $limit++);
$tree .= '</li>';
}
}
$tree .= '</ul>';
return $tree;
}
echo generateTreeMenu($items);
//index elements by id
foreach ($items as $item) {
$item['subs'] = array();
$indexedItems[$item['id']] = (object) $item;
}
//assign to parent
$topLevel = array();
foreach ($indexedItems as $item) {
if ($item->parent_id == 0) {
$topLevel[] = $item;
} else {
$indexedItems[$item->parent_id]->subs[] = $item;
}
}
//recursive function
function renderMenu($items) {
$render = '<ul>';
foreach ($items as $item) {
$render .= '<li>' . $item->title;
if (!empty($item->subs)) {
$render .= renderMenu($item->subs);
}
$render .= '</li>';
}
return $render . '</ul>';
}
echo renderMenu($topLevel);
The problem here is just the structure of the array, so first you can convert the array to a more suitable structure, then you can draw your list easily.
Here is a function to convert the array:
function makeTree( $rst, $level, &$tree )
{
for ( $i=0, $n=count($rst); $i < $n; $i++ )
{
if ( $rst[$i]['parent_id'] == $level )
{
$branch = array(
'id' => $rst[$i]['id'],
'title' => $rst[$i]['title'],
'children' => array()
);
makeTree( $rst, $rst[$i]['id'], $branch['children'] );
$tree[] = $branch;
}
}
}
Mode of use:
$tree = array();
makeTree( $originalArray, 0, $tree );
At the end, you will have a new array in $tree structured as shown below, which you can easily draw in your view.
Array
(
[0] => Array
(
[id] => 1
[title] => menu1
[children] => Array
(
[0] => Array
(
[id] => 2
[title] => submenu1-1
[children] => Array
(
)
)
[1] => Array
(
[id] => 3
[title] => submenu1-2
[children] => Array
(
)
)
)
)
[1] => Array
(
[id] => 4
[title] => menu2
[children] => Array
(
[0] => Array
(
[id] => 5
[title] => submenu2-1
[children] => Array
(
)
)
)
)
)
Try this
$node = array();
foreach ($items as $item) {
if ($item['parent_id'] == 0) {
$node[$item['id']][$item['id']] = $item['title'];
} else {
$node[$item['parent_id']][$item['id']] = $item['title'];
}
}
$result = array();
foreach ($node as $key => $value) {
$result[$value[$key]] = array_diff($value, array($key => $value[$key]));
}

PHP: Iterating through array?

I want a function that
searches through my array, and
returns all the
children to a specific node. What is
the most appropriate way to do this?
Will recursion be necessary in this case?
I have previously constructed a few quite complex functions that iterates with or without the help of recursion through multi-dimensional arrays and re-arranging them, but this problem makes me completely stuck and I can't just get my head around it...
Here's my array:
Array
(
[1] => Array (
[id] => 1
[parent] => 0
)
[2] => Array (
[id] => 2
[parent] => 1
)
[3] => Array (
[id] => 3
[parent] => 2
)
)
UPDATE:
The output which I want to get. Sorry for the bad example, but I'll blame it on lack of knowledge on how to format the stuff I need to do :)
function getAllChildren($id) {
// Psuedocode
return $array;
}
getAllChildren(1); // Outputs the following:
Array
(
[2] => Array (
[id] => 2
[parent] => 1
)
[3] => Array (
[id] => 3
[parent] => 2
)
)
$nodes = array( 1 => array ( 'id' => 1,
'parent' => 0
),
2 => array ( 'id' => 2,
'parent' => 1
),
3 => array ( 'id' => 3,
'parent' => 2
)
);
function searchItem($needle,$haystack) {
$nodes = array();
foreach ($haystack as $key => $item) {
if ($item['parent'] == $needle) {
$nodes[$key] = $item;
$nodes = $nodes + searchItem($item['id'],$haystack);
}
}
return $nodes;
}
$result = searchItem('1',$nodes);
echo '<pre>';
var_dump($result);
echo '</pre>';
Non-recursive version of the searchItem() function:
function searchItem($needle,$haystack) {
$nodes = array();
foreach ($haystack as $key => $item) {
if (($item['parent'] == $needle) || array_key_exists($item['parent'],$nodes)) {
$nodes[$key] = $item;
}
}
return $nodes;
}
(assumes ordering of the parents/children, so a child node isn't included in the array unless the parent is already there)
<?php
function searchItem($needle)
{
foreach ($data as $key => $item)
{
if ($item['id'] == $needle)
{
return $key;
}
}
return null;
}
?>
Check out the array_walk_recursive() function in PHP:
http://www.php.net/manual/en/function.array-walk-recursive.php

PHP: Formatting multi-dimensional array as HTML?

I have tried to get my head around building a recursive function to handle formatting of a unknown depth multi-dimensional array to HTML and nested Divs. I thought that it should be a piece of cake, but no.
Here's what I have come up with this far:
function formatHtml($array) {
$var = '<div>';
foreach ($array as $k => $v) {
if (is_array($v['children']) && !empty($v['children'])) {
formatHtml($v['children']);
}
else {
$var .= $v['cid'];
}
}
$var.= '</div>';
return $var;
}
And here's my array:
Array
(
[1] => Array
(
[cid] => 1
[_parent] =>
[id] => 1
[name] => 'Root category'
[children] => Array
(
[2] => Array
(
[cid] => 2
[_parent] => 1
[id] => 3
[name] => 'Child category'
[children] => Array ()
)
)
)
)
You're missing only one important piece: when you make the recursive call to formatHtml() you're not actually including the returned content anywhere! Append it to $var and you should get much better results:
function formatHtml($array) {
$var = '<div>';
foreach ($array as $k => $v) {
if (is_array($v['children']) && !empty($v['children'])) {
$var .= formatHtml($v['children']);
}
else {
$var .= $v['cid'];
}
}
$var.= '</div>';
return $var;
}

Categories