0

My main problem is that I want to generate an unordered list in HTML using PHP. I get the data from a SQL query which then needs to be concated into an unordered list using a PHP function I tried to write myself. Every item should be a li and if it has a subitem, it should open a new ul with the subitems as li which again can contain subitems, etc.

I have an array where I output every part of a tree itself. It looks like this:

[0] => Array (
    [0] => Application Integration
    [1] => 
    )
[1] => Array (
    [0] => Application Integration
    [1] => Windows
    [2] => 
    )
[2] => Array (
    [0] => Application Integration
    [1] => Windows
    [2] => Leitungen
    )
[3] => Array (
    [0] => Application Integration
    [1] => Windows
    [2] => Leitungen
    [3] => WAN
    )
[4] => Array (
    [0] => Application Integration
    [1] => Windows
    [2] => Leitungen
    [3] => Mail
    )
[5] => Array (
    [0] => Application Integration
    [1] => Windows
    [2] => EDI
    )
[6] => Array (
    [0] => Application Integration
    [1] => Windows
    [2] => EDI
    [3] => Word
    )
[7] => Array (
    [0] => Application Integration
    [1] => Windows
    [2] => EDI
    [3] => LAN
    )
[8] => Array (
    [0] => Application Integration
    [1] => Internet
    [2] => 
    )
[9] => Array (
    [0] => Application Integration
    [1] => Internet
    [2] => Office
    )
[10] => Array (
    [0] => Application Integration
    [1] => Internet
    [2] => Office
    [3] => Powerpoint
    )
[11] => Array (
    [0] => Application Integration
    [1] => Internet
    [2] => Office
    [3] => Excel
    )
[12] => Array (
    [0] => Application Integration
    [1] => Internet
    [2] => Leitungen
    )
[13] => Array (
    [0] => Application Integration
    [1] => Internet
    [2] => Leitungen
    [3] => SQL Developer
    )
[14] => Array (
    [0] => Application Integration
    [1] => Internet
    [2] => Leitungen
    [3] => Pokerstars
    )

I want the output to be surrounded by an unordered list where every item in the array is a list element and if it has a subitem it should also be in an unordered list, ... It should look like the following list:

<ul>
  <li>
    Applicaton Integration
    <ul>
      <li>
        Windows 
        <ul>
          <li>
            EDI
            <ul>
              <li>Word</li>
              <li>LAN</li>
            </ul>
          </li>
        </ul>
      </li>
      <li>
        Internet
        <ul>
          <li></li>
        </ul>
      </li>
    </ul>
  </li>
</ul>
...etc

I tried to write the following function in PHP but it is not quite what i wanted since it closes the tags to early and/or too late.

function treeOut(array $tree): string{
  $markup = '';
  print_r($tree);
  foreach($tree as $branch) {
    if(!empty($branch[1])){
      $markup.='<ul class="Stufe1">';
      $markup.='<li>';
        if(!empty($branch[2])){
          $markup.='<ul class="Stufe2">';
          $markup.='<li>';
            if(!empty($branch[3])){
              $markup.='<ul class="Stufe3">';
              $markup.='<li>';
              $markup.='<input type="checkbox" name=""/>'.$branch[3];
              $markup.='</li></ul>';
            }else{
              $markup.='<input type="checkbox" name=""/>'.$branch[2];
            }
            $markup.='</ul></li>';
          }else{
          $markup.='<input type="checkbox" name=""/>'.$branch[1];
        }
        $markup.='</li></ul>';
    }else{
      $markup.='<li><input type="checkbox" name=""/>'.$branch[0];
    }
  }
  return $markup;
}

I am sorry for that much code but I would appreciate any help.

2
  • 1
    If you have an undefined (or at least, not always the same) depth of your array i would recommend to use recursion, e.g. call your function with a sub-array when it contains more items, so you have to write less code. Commented Aug 3, 2017 at 9:25
  • 1
    you can try to merge all different elements of first level in one subarray, then the second level in other subarray and go on... Then easy going recursive throw all levels and create markup Commented Aug 3, 2017 at 9:37

1 Answer 1

1

To solve a problem involving nested levels of data structures that should however be treated roughly the same way, recursivity is your best friend.

In case you aren't familiar with this technique, the idea is to design a function that will call itself.

Regarding your problem, we can consider something like this :

First, a function to modify your array so that it can be treated.

function nester(array $array, $idx = 0) {
    if (array_key_exists($idx, $array) && !empty($array[$idx])) {
        return array($array[$idx] => nester($array, $idx + 1));
    }
    return array();
}

function treeParser(array $array_tree) {
    $dom_tree = '';
    foreach ($array_tree as $key => $val) {
        if (is_array($val) && count($val)) {
            $dom_tree .= "<li>$key".treeParser($val).'</li>';
        } else {
            $dom_tree .= "<li>$key</li>";
        }
    }
    return ($dom_tree ? "<ul>$dom_tree</ul>" : '');
}

$array_nested = array();

foreach ($array as $value) {
    $array_nested[] = nester($value);
}
$DOM_tree = treeParser(array_merge_recursive(... $array_nested));

Beforehand, a function browses each of your subarrays and convert them to nested arrays so tht we can recurse on them. With some help from array_merge_recursive, these arrays are merged into a clean tree of the DOM you seek to build.

The other function then takes your array as a parameter and browses it with a foreach. Each time it finds an array, it appends a pair of <li> tags containing the current array's key, and eventually the return of itself called on that array provided it isn't empty. When an instance of the function has treated its whole subarray, it returns its work - the string $dom_tree - between <ul> tags. If that instance was the main one - the one you called yourself - these <ul> tags will be the main unordered list containing your whole data structure.

It theorically works whatever the depth of your array is, but beware the Stack Overflow if it's insanely deep.

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

7 Comments

this solution does only work with a more nested array. in my case it only outputs every item on the same stage.
My bad, I misinterpreted your example.
@Gabsii Damn, your array is the hell not optimised for your purpose.
@Gabsii Edited. It should work with your format now.
assuming that $array is the input array, i still got the wrong output. see jsfiddle.net/zx5dbn35/4
|

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.