递归菜单问题

I have been messing around with recursion a few hours and just cant get it right!

I want my menu structure to be:

<ul>
   <li> menu 1 <ul>
      <li> menu 1.1 <ul>
         <li> menu 1.1.1 </li>
      </ul>
   </ul>
<li> menu 2 </li>
<li> menu 3 <ul>
   <li> menu 3.1 </li>
</ul>
<li> menu 4 </li>
</ul>
</li>

but i just cant get it right.

    print '<ul>';
    display_children(0, 0);
function display_children($parent, $level) {
   // retrieve all children of $parent

   $result = mysql_query('SELECT * FROM kategori WHERE parent="'.$parent.'";');

   while ($row = mysql_fetch_array($result)) {

       if($row['parent']!=0)
            print '<ul>';
       print '<li>';

       // indent and display the title of this child
       echo $row['navn']."
";

       // call this function again to display this
       // child's children
       display_children($row['id'], $level+1);

   }

        print '</li>';
           print '</ul>';

as it is now, it prints the right structure but poops out a crapton of missplaced <ul> and <il>

my top level menu items have 0 as parent (to indicate that they are the absolut top) and its children have their respective parents id as parent attribut.

i tried to check if the current run through of the function (lets say we were at menu 1.1.1) had parent 0 which, to my surprise, was true as i would have thought the current run through would have have parent "menu 1.1" instead of "menu 1"

Any one able to help me out here? I have been staring at that damn code for waaay to long and if you have a quick fix to how i can get this code snippet to insert UL and IL the right places i would be most grateful!

Thanks in advance, Rasmus

display_children is perhaps not the best name, something like display_menu_level might be more descriptive. Think about what it has to do: display a <ul>, then a number of children, then a </ul>. Each child is an <li>, the "navn" text, a submenu, and an </li>. Just reflect that structure in code, something like this:

function display_menu_level($parent, $level) {
    $results = mysql_query('SELECT * FROM kategori WHERE parent="'.$parent.'";');

    // Don't print an empty list ("<ul></ul>")
    if (mysql_num_rows($results) == 0) return;

    // Start the menu
    echo '<ul>';

    // Display children
    while ($row = mysql_fetch_array($result)) {
        // Start this child
        print '<li>';

        // indent and display the title of this child
        echo $row['navn']."
";

        // call this function again to display this
        // child's children
        display_children($row['id'], $level+1);

        // Close this child
        print '</li>';
    }

    // Close the menu
    print '</ul>';
}

Some pseudo-code might put you on the right track:

function display_child_menus(parent_id) {

  menus = get_from_db_having_parent(parent_id)

  echo UL

  foreach (menus as menu) {

    echo LI

    echo menu->title

    children = get_menu_children(id)

    if (menu->has_children) {
      echo display_child_menus(menu->id)
    }

    echo /LI
  }

  echo /UL
}

echo display_child_menus(0)

Notice how it is indented and how much easier to read it is than the code you have posted. This helps a lot in finding what is wrong.

Also notice how I have no mixed database stuff with displaying the data. Make separate functions (here you can see the function get_from_db_having_parent)

You forget to add the opening <li> tag.

Also, instead of printing directly, store each tag in a an array first.

$parents = array();
While( parent exists )
{
  //  Query for children again
        $children = array();
         While(children exist)
         {
              $children[] = $row2[navn] ;
         }

        $parents[$row[navn]] = $children; 

        Unset($children);
}

Now use a foreach to display:

Echo "<ul>"; 
Foreach ($parents as $k => $v)
{
     Echo "<li>".$k; 
     If (!empty($v))
    {
           Echo "<ul>"; 
           Foreach($v as $z)
           {
                 Echo "<li>".$z."</li>"; 
            }
            Echo "</ul>"; 
     }
     Echo "</li>"; 
}
Echo "</ul>";

I typed on a phone so pardon any errors. I made this a wiki so guys could help edit it. Btw this is untested. But there shouldn't be any bugs.