Reputation: 15673
Imagine you have an array of HTML elements (in their appearance order) as
$array = array(
1=>array( 'level' => 1, 'element' => '<div class="parent">'),
2=>array( 'level' => 2, 'element' => '<div class="child">'),
3=>array( 'level' => 3, 'element' => '<span class="child2">'),
4=>array( 'level' => 2, 'element' => '<div class="child">'),
5=>array( 'level' => 2, 'element' => '<div class="child">'),
6=>array( 'level' => 3, 'element' => '<span class="child2">'),
7=>array( 'level' => 4, 'element' => '<span class="child3">'),
);
How do you plan a foreach
loop to find the places of the closing HTML tags to output a string as
<div class="parent">
<div class="child">
<span class="child2">
<span>
</div>
<div class="child">
</div>
<div class="child">
<span class="child2">
<span class="child3">
</span>
</span>
</div>
</div>
My attempt was something like
foreach($array as $e){
echo $e['element'];
$level = $e['level'];
if($level<=$previous_level) {
echo $closing;
$closing = '';
}
$closing.= '</'. $element . '>'; // which comes from parsed $e['element'];
$previous_level = $level;
}
Upvotes: 3
Views: 1363
Reputation: 33238
Here is my solution using recursive function:
$array = array(
1 => array('level' => 1, 'element' => '<div class="parent">', 'parsedElement' => 'div'),
2 => array('level' => 2, 'element' => '<div class="child">', 'parsedElement' => 'div'),
3 => array('level' => 3, 'element' => '<span class="child2">', 'parsedElement' => 'span'),
4 => array('level' => 2, 'element' => '<div class="child">', 'parsedElement' => 'div'),
5 => array('level' => 2, 'element' => '<div class="child">', 'parsedElement' => 'div'),
6 => array('level' => 3, 'element' => '<span class="child2">', 'parsedElement' => 'span'),
7 => array('level' => 4, 'element' => '<span class="child3">', 'parsedElement' => 'span'),
);
function displayTree(&$tree, $level = 1) {
if (!$tree) {
return;
}
$el = array_shift($tree); // get the current element
echo $el['element'];
if ($tree && $tree[0]['level'] > $level) {
// if the next item is a child of this then increase the level and process the sub-tree
displayTree($tree, $level+1);
}
echo '</'. $el['parsedElement'] . '>';
if ($tree && $tree[0]['level'] < $level) {
return; // go back to the parent
}
displayTree($tree, $el['level']); // process the next sibling
}
displayTree($array);
Output:
<div class="parent">
<div class="child">
<span class="child2"></span>
</div>
<div class="child"></div>
<div class="child">
<span class="child2">
<span class="child3"></span>
</span>
</div>
</div>
Upvotes: 3
Reputation: 28529
You can do it with stack,
$array = array(
1=>array( 'level' => 1, 'element' => '<div class="parent">'),
2=>array( 'level' => 2, 'element' => '<div class="child">'),
3=>array( 'level' => 3, 'element' => '<span class="child2">'),
4=>array( 'level' => 2, 'element' => '<div class="child">'),
5=>array( 'level' => 2, 'element' => '<div class="child">'),
6=>array( 'level' => 3, 'element' => '<span class="child2">'),
7=>array( 'level' => 4, 'element' => '<span class="child3">'),
);
$result = "";
$tags = []; // stack to store node end tag
$levels = []; // stack to store node level
foreach($array as $tag){
$level = $tag["level"];
$element = $tag["element"];
while(end($levels) >= $level){ // pop all Sibling and their child
array_pop($levels);
$result .= array_pop($tags);
}
$result .= str_pad("",$level-1,"\t") . $element . "\n";
array_push($tags, str_pad("",$level-1,"\t") . "</" .substr($element,1,strpos($element," ")-1) . ">\n");
array_push($levels,$level);
}
while(end($levels)){
array_pop($levels);
$result .= array_pop($tags);
}
echo $result;
And the result,
php test.php
<div class="parent">
<div class="child">
<span class="child2">
</span>
</div>
<div class="child">
</div>
<div class="child">
<span class="child2">
<span class="child3">
</span>
</span>
</div>
</div>
Upvotes: 3