1

I want to make a select tree for my category. Here is for unordered list.

function generate_menu($parent, $menu_array = null)
{
    $has_childs = false;
    foreach ($menu_array as $key => $value) {
        if ($value['parent'] == $parent) {
            if ($has_childs === false) {
                $has_childs = true;
                echo "<ul>\n";
            }
            echo '<li><a href="#">'.$value['name'].'</a>';
            generate_menu($key, $menu_array);
            echo "</li>\n";
        }
    }
    if ($has_childs === true)
        echo "</ul>\n";
}

Here is the HTML output for unordered list.

<ul>
  <li>
    Ford
    <ul>
      <li>
        Falcon
        <ul>
          <li>
            Futura
            <ul>
              <li>FPV</li>
              <li>GT</li>
              <li>F6</li>
              <li>GS</li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
  <li>F150</li>
  <li>Festiva</li>
</ul>

Question : How to make the current function for select option and the results will be something like this.

<select name="categories">
    <option value="Ford">Ford</option>
    <option value="Falcon">-Falcon</option>
    <option value="Futura">--Futura</option>
    <option value="FPV">--FPV</option>
    <option value="GT">---GT</option>
    <option value="F6">---F6</option>
    <option value="GS">---GS</option>
    <option value="F150">-F150</option>
    <option value="Festiva">-Festiva</option>
</select>
user1286499
  • 227
  • 2
  • 13
  • replace `ul` with `select`, and `li` with `option` – Ibu Jan 04 '13 at 23:20
  • Please add also the HTML output of the ul/li list to your question. It's normally easy to convert that into the strings you want to use for the select. – hakre Jan 04 '13 at 23:20
  • @Ibu Yes sure, if in unordered list, it has `
    • ` to separate the children. On select option I want to add `- Sub`, `--Sub`, `---Sub`.
    – user1286499 Jan 04 '13 at 23:25
  • 1
    If you want to generate the `option` like you did with the `ul`, you need to provide another parameter for the `$level`. Each time you go into the function you increase the `$level` by one and each time you go out there, you decrease by one (that is beginning and end of the function in your case). Default value for `$level` is 0. – hakre Jan 05 '13 at 00:00

1 Answers1

4

I would go with the text-list you have already, it's a breeze to turn it into the <select> element:

$list = <<<LIST
Ford
| Falcon
| | Futura
| | FPV
| | | GT
| | | F6
| | | GS
| F150
| Festiva
LIST;

echo '<select name="categories">', "\n";
foreach (explode("\n", $list) as $entry) {
    $label = strtr($entry, ['| ' => '-']);
    $value = trim($entry, ' |');
    printf("  <option value=\"%s\">%s</option>\n", htmlspecialchars($value), htmlspecialchars($label));
};
echo "</select>\n";

Output:

<select name="categories">
  <option value="Ford">Ford</option>
  <option value="Falcon">-Falcon</option>
  <option value="Futura">--Futura</option>
  <option value="FPV">--FPV</option>
  <option value="GT">---GT</option>
  <option value="F6">---F6</option>
  <option value="GS">---GS</option>
  <option value="F150">-F150</option>
  <option value="Festiva">-Festiva</option>
</select>

Otherwise if you were unable to generate this text-list but only the ul/li list, then work on that HTML but in the same fashion.

After you've updated and provided the HTML, here is it working of the ul/li list string ($ul) (PHP 5.4):

echo '<select name="categories">', "\n";
foreach ((new SimpleXMLelement($ul))->xpath('//li') as $li) {
    $label = htmlspecialchars(trim($li->xpath('text()[1]')[0]));
    $level = count($li->xpath('ancestor::li'));
    printf(
        "  <option value=\"%s\">%s%s</option>\n",
        $label, str_repeat('-', $level), $label
    );
}
echo "</select>\n";

How this works is outlined more in this earlier answer of mine: How can I extract structured text from an HTML list in PHP?. That one is with DomDocument not SimpleXMLElement like here, however, the more or less main part is the xpath here which both provide.

This is all fine and dandy. However you somewhat must have missed to actually provide the sample array - I just now assumed:

array (
  1 => 
  array (
    'parent' => 0,
    'name' => 'Ford',
  ),
  2 => 
  array (
    'parent' => 1,
    'name' => 'Falcon',
  ),
  3 => 
  array (
    'parent' => 2,
    'name' => 'Futura',
  ),
  4 => 
  array (
    'parent' => 3,
    'name' => 'FPV',
  ),
  5 => 
  array (
    'parent' => 3,
    'name' => 'GT',
  ),
  6 => 
  array (
    'parent' => 3,
    'name' => 'F6',
  ),
  7 => 
  array (
    'parent' => 3,
    'name' => 'GS',
  ),
  8 => 
  array (
    'parent' => 0,
    'name' => 'F150',
  ),
  9 => 
  array (
    'parent' => 0,
    'name' => 'Festiva',
  ),
)

to point you to some method that is aligned with what you already do for the ul/li list, a recursive function that works with your array:

function generate_dropdown($menu_array, $parent = 0, $level = -1) {
    ++$level || print('<select name="categories">'. "\n");
    foreach ($menu_array as $key => $value) {
        if ($value['parent'] != $parent) continue;
        $label = htmlspecialchars($value['name']);
        printf("  <option value=\"%s\">%s%s</option>\n", $label, str_repeat('-', $level), $label);
        generate_dropdown($menu_array, $key, $level);
    }
    $level-- || print('</select>');
}

generate_dropdown($array);

Output:

<select name="categories">
  <option value="Ford">Ford</option>
  <option value="Falcon">-Falcon</option>
  <option value="Futura">--Futura</option>
  <option value="FPV">---FPV</option>
  <option value="GT">---GT</option>
  <option value="F6">---F6</option>
  <option value="GS">---GS</option>
  <option value="F150">F150</option>
  <option value="Festiva">Festiva</option>
</select>
Community
  • 1
  • 1
hakre
  • 193,403
  • 52
  • 435
  • 836
  • Excellent! thank you so much @hakre. You made my day. Paypal button should be in your profile :) – user1286499 Jan 05 '13 at 00:38
  • It's possible to add parent name to chilren ``, `` – user1286499 Jan 07 '13 at 14:49
  • 1
    yes, that is possible. The [this answer shows that for the `CHILDREN` column](http://stackoverflow.com/a/14086249/367456) in the output (you turn that into a list of parents by changing the xpath axis from `./ul/li` to `./ancestor::li`), see as well xpath axes here: http://dret.net/lectures/xml/xpath#xpath-axes – hakre Jan 07 '13 at 15:02
  • 1
    If your array list is sorted, it's also possible to obtain the parents by making `$level` an array of parent elements. The count of it provides the level and the array would give you parents stuff, like their labels. Let me cook that up, I think I still have the code on platter. – hakre Jan 07 '13 at 15:18
  • currently i use your `generate_dropdown` function. – user1286499 Jan 07 '13 at 18:04
  • 1
    Yes that would be it. Was distracted, need to see if and when I add it here. It's basically like how I outlined. – hakre Jan 07 '13 at 20:24
  • I got it :) First i rebuild the array http://stackoverflow.com/a/10332361/1286499 then http://stackoverflow.com/a/6812689/1286499 and cool! – user1286499 Jan 07 '13 at 21:00