3

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;
}
7
  • What you have tried so far? Commented Aug 10, 2019 at 9:34
  • @RakeshJakhar I tried to store the closing tag in a string/array when looping, but couldn't release the stored closings tag at the right time. Commented Aug 10, 2019 at 9:37
  • So ... show us some code. Commented Aug 10, 2019 at 9:41
  • @Marcel I added a simplified code for your reference. Commented Aug 10, 2019 at 9:48
  • Why don't you order them as a tree and go recursive about it ? Way easier Commented Aug 10, 2019 at 10:01

2 Answers 2

3

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>

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

Comments

3

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>

Comments

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.