Jump to content

PHP Recursive Multidimensional Array to HTML nested code


rod25

Recommended Posts

Hello, 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!

 

 




			
		
Link to comment
Share on other sites

i think this will do it

function recursive($array, $level = 0) {
    foreach($array as $key => $value) {
        if (is_array($value)) {
          echo str_repeat(" ", $level), "[".$value['tag']."]<br>", '';
          if (@$value['children']) {
            recursive($value['children'], $level + 1);
          }
          echo str_repeat(" ", $level), "[/".$value['tag']."]<br>", '';
        }
    }
}
Link to comment
Share on other sites

After creating your multi-dimensional array, you can use this to output the content. I put in logic to add spacing at each level to make it easy to "see" the structure of the HTML.

 

 

<?php
function createOutput($array, $level=0)
{
    //Create variable to hold output
    $output = '';
    //Create number of tabs for spacing the level
    $tabs = str_repeat ("    ", $level);
    //Iterate through each element in the current level
    foreach($array as $record)
    {
        //Open div for the current record
        $output .= "{$tabs}<div id=\"{$record['id']}\">\n";
        //Show current record name
        $output .= "{$tabs}\t{$record['tag']}\n";
        //Check if there are children
        if(isset($record['children']) && count($record['children']))
        {
            //Include children output
            $output .= createOutput($record['children'], $level+1);
        }
        //Close div for current record
        $output .= "{$tabs}</div>\n";
    }
    //Return the results
    return $output;
}
?>

 

Output

 

<div id="1">
    div1
    <div id="2">
        div2
        <div id="3">
            div3
        </div>
        <div id="4">
            div4
        </div>
    </div>
</div>
<div id="5">
    div5
    <div id="6">
        div6
    </div>
</div>
<div id="7">
    div7
</div>
Link to comment
Share on other sites

Oh yeah. I've reinvented this wheel a few times.

 

Inevitably you will find yourself in a situation where you want to manipulate attributes on the tag or change the tag from a div to an li or span or something else.

 

My preferred approach is to use an actual html dom building tool like querypath so that you can construct your html using methods that feel just like jQuery and cache the result.

 

https://github.com/technosophos/querypath

Edited by thinsoldier
Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.