Member Avatar for iamthwee

Hi I have a flat array listed in the format below:

    id      parent  tag htmlcontent

    2-0     null    li  |home|
    1-0     2-0     ol  
    0-0     1-0     li  |about|
    6-0     null    li  |a|
    5-0     6-0     ol  
    4-0     5-0     li  |b|
    3-0     4-0     ol  
    2-1     3-0     li  |c|
    1-1     2-1     ol  
    0-1     1-1     li  |d|

I would like to build a recursive function to generate an unordered list eg..

<li>
  <ol>
   <li> home</li>
   <li> about </li>
  </ol>
...etc

How can I do this?

Recommended Answers

All 14 Replies

Member Avatar for iamthwee

No one can help? Null is the top level parent.

Member Avatar for diafol

Erm, I don't think that's a great way of storing the data. You've gone for some type of 'adjacency list' method? I think I suggested 'nested sets' a while ago - although cheap reads, expensive writes.

http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

I think you'll find it easier inthe long run, but it takes a little while to get your head around it. I posted an article on it before - but that was for binary trees - same sort of idea though. Here's an image of the model:

http://mikehillyer.com/media//numbered_tree.png

Hi, I don't understand the scheme, how it works the relation between id and parent?

Member Avatar for iamthwee

Hi, I don't understand the scheme, how it works the relation between id and parent?

The hypens are misleading, just consider it to be a unique id, as an example the about page has an id of 0-0 and its parent is the <ol> id 1-0.

You've gone for some type of 'adjacency list' method?

Not quite sure what you mean... it is a basic parent child relationship. I should be able to recurse through and build the list, but I need some help.

Full code would be appreciated.

Ta.

Member Avatar for iamthwee

The array about should generate the list shown. 6923a6d4e44eb5a69adadcb82d86b684

In the diagram menu 'd' should come after menu 'c' I made a mistake with the attached picture.

The 'tag' is just for my reference telling me if it is a <li> or a <ol>

Member Avatar for diafol

I undestood your table - just not sure if you need all the extras - ol/li - and the need for | around the labels.

To explain the left and right values can be imagined as bus stop number as your finger traces its way around the drawn out hierarchy. Something like this... (original image from the link in previous post)...

f1aa4a142804a16421f16f62c3d02ae0

And also from the same excellent resource:

We can retrieve the full tree through the use of a self-join that links parents with nodes on the basis that a node’s lft value will always appear between its parent’s lft and rgt values:

SELECT node.name
FROM nested_category AS node,
        nested_category AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
        AND parent.name = 'ELECTRONICS'
ORDER BY node.lft;

Once again: http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

commented: thanks but I'm not looking to change the structure +14
Member Avatar for iamthwee

I can't change my db structure now diafol, plus I don't want to. It took ages to write a parser to extract the data from a complicated div. All I have is a flat array like the one above, I do agree some of the ols are unnecessary but that's just how the parser dumps it. I can NOT change this.

Just looking for a way to simply create a list from that data, complete code is what I'm after... using recursion.

Can anyone help... surely this must be easy.

Member Avatar for diafol

I can't change my db structure now diafol, plus I don't want to

OK

Just looking for a way to simply create a list from that data, complete code is what I'm after... using recursion.

Heh heh - users asking for complete code usually get blasted. Spending a lot of time on something is not a reason to not use a better method, however, good luck with it, hope you get a solution :)

Member Avatar for iamthwee

ok here is my attempt:

<?php 

 /**
  *  @Description: to build a recursive list from array
  *       @Params: array
  *
  *      @returns: list
  */

  // 2-0     null    li  |home|
  //   1-0     2-0     ol  
  //   0-0     1-0     li  |about|
  //   6-0     null    li  |a|
  //   5-0     6-0     ol  
  //   4-0     5-0     li  |b|
  //   3-0     4-0     ol  
  //   2-1     3-0     li  |c|
  //   1-1     2-1     ol  
  //   0-1     1-1     li  |d|


$arrayName[0] = array('id' => '2-0', 'parent' => 'null', 'tag' => 'li', 'name' => 'home' );
$arrayName[1] = array('id' => '1-0', 'parent' => '2-0', 'tag' => 'ol', 'name' => '' );
$arrayName[2] = array('id' => '0-0', 'parent' => '1-0', 'tag' => 'li', 'name' => 'about' );
$arrayName[3] = array('id' => '6-0', 'parent' => 'null', 'tag' => 'li', 'name' => 'a' );
$arrayName[4] = array('id' => '5-0', 'parent' => '6-0', 'tag' => 'ol', 'name' => '' );
$arrayName[5] = array('id' => '4-0', 'parent' => '5-0', 'tag' => 'li', 'name' => 'b' );
$arrayName[6] = array('id' => '3-0', 'parent' => '4-0', 'tag' => 'ol', 'name' => '' );
$arrayName[7] = array('id' => '2-1', 'parent' => '3-0', 'tag' => 'li', 'name' => 'c' );
$arrayName[8] = array('id' => '1-1', 'parent' => '2-1', 'tag' => 'ol', 'name' => '' );
$arrayName[9] = array('id' => '0-1', 'parent' => '1-1', 'tag' => 'li', 'name' => 'd' );



 for ($i=0; $i < 9 ; $i++) 
 {

    echo $arrayName[$i]['id'];
    echo " ". $arrayName[$i]['parent'];
    echo " ". $arrayName[$i]['tag'];
    echo " ". $arrayName[$i]['name'];
    echo ('<br/>');
 }

  /**
   *  @Description: recursive function to build list
   *       @Params: --
   *
   *     @returns: --
   */

function buildNavigation($items, $parent = "null")
{
    $hasChildren = false;
    $outputHtml = '<ul>%s</ul>';
    $childrenHtml = '';

    foreach($items as $item)
    {
        if ($item['parent'] == $parent) {
            $hasChildren = true;
            $childrenHtml .= '<li>'.$item['name'];         
            $childrenHtml .= buildNavigation($items, $item['id']);         
            $childrenHtml .= '</li>';           
        }
    }

    // Without children, we do not need the <ul> tag.
    if (!$hasChildren) {
        $outputHtml = '';
    }

    // Returns the HTML
    return sprintf($outputHtml, $childrenHtml);
}

print buildNavigation($arrayName);



 ?>

it is working but giving me extra uls

<ul>
    <li>home
        <ul>
            <li>
                <ul>
                    <li>about</li>
                </ul>
            </li>
        </ul>
    </li>
    <li>a
        <ul>
            <li>
                <ul>
                    <li>b
                        <ul>
                            <li>
                                <ul>
                                    <li>c
                                        <ul>
                                            <li>
                                                <ul>
                                                    <li>d</li>
                                                </ul>
                                            </li>
                                        </ul>
                                    </li>
                                </ul>
                            </li>
                        </ul>
                    </li>
                </ul>
            </li>
        </ul>
    </li>
</ul>
Member Avatar for iamthwee

I need to somehow reduce my array to :

$arrayName[0] = array('id' => '2-0', 'parent' => 'null', 'tag' => 'li', 'name' => 'home' );
$arrayName[1] = array('id' => '0-0', 'parent' => '2-0', 'tag' => 'li', 'name' => 'about' );
$arrayName[2] = array('id' => '6-0', 'parent' => 'null', 'tag' => 'li', 'name' => 'a' );
$arrayName[3] = array('id' => '4-0', 'parent' => '6-0', 'tag' => 'li', 'name' => 'b' );
$arrayName[4] = array('id' => '2-1', 'parent' => '4-0', 'tag' => 'li', 'name' => 'c' );
$arrayName[5] = array('id' => '0-1', 'parent' => '2-1', 'tag' => 'li', 'name' => 'd' );

i.e get rid of the uls but shift up the parent child relationship.

Member Avatar for iamthwee

not pretty but:

<?php 

 /**
  *  @Description: to build a recursive list from array
  *       @Params: array
  *
  *      @returns: list
  */

  // 2-0     null    li  |home|
  //   1-0     2-0     ol  
  //   0-0     1-0     li  |about|
  //   6-0     null    li  |a|
  //   5-0     6-0     ol  
  //   4-0     5-0     li  |b|
  //   3-0     4-0     ol  
  //   2-1     3-0     li  |c|
  //   1-1     2-1     ol  
  //   0-1     1-1     li  |d|


$arrayName[0] = array('id' => '2-0', 'parent' => 'null', 'tag' => 'li', 'name' => 'home' );
$arrayName[1] = array('id' => '1-0', 'parent' => '2-0', 'tag' => 'ol', 'name' => 'kkkkkkkk' );
$arrayName[2] = array('id' => '0-0', 'parent' => '1-0', 'tag' => 'li', 'name' => 'about' );
$arrayName[3] = array('id' => '6-0', 'parent' => 'null', 'tag' => 'li', 'name' => 'a' );
$arrayName[4] = array('id' => '5-0', 'parent' => '6-0', 'tag' => 'ol', 'name' => '' );
$arrayName[5] = array('id' => '4-0', 'parent' => '5-0', 'tag' => 'li', 'name' => 'b' );
$arrayName[6] = array('id' => '3-0', 'parent' => '4-0', 'tag' => 'ol', 'name' => '' );
$arrayName[7] = array('id' => '2-1', 'parent' => '3-0', 'tag' => 'li', 'name' => 'c' );
$arrayName[8] = array('id' => '1-1', 'parent' => '2-1', 'tag' => 'ol', 'name' => '' );
$arrayName[9] = array('id' => '0-1', 'parent' => '1-1', 'tag' => 'li', 'name' => 'd' );


 /**
  *  @Description: cleans  the array removing ul tags and shifting 
  *                the parent child relationship.
  *                1.loop through select parent  -> id 
  *                2. Check if  tag is ol
  *                3. If it is change original parent to id
  *                4. Remove ul array (not sure if this is necessary)
  *       @Params: params
  *
  *     @returns: returns
  */

 clean_array($arrayName);

 function clean_array($arrayName)
 {

    for ($i=0; $i < count($arrayName); $i++) { 

      if (is_parent_ol($arrayName[$i]['parent'],$arrayName))  
      {
         //$arrayName[$i]['parent'] =
          $tmp =get_new_parent($arrayName[$i]['parent'],$arrayName);
          $arrayName[$i]['parent'] = $tmp;
        echo ('<br/>');
      }
      else
      {
        //do nothing!!
      }


    }

    hai($arrayName);
 }

 function is_parent_ol($id,$arrayName)
 {
  //echo $id;
    $my_counter = 0;
    for ($i=0; $i < count($arrayName); $i++) { 
      if($arrayName[$i]['id']==$id)
      {
        if($arrayName[$i]['tag'] == "ol")
        {
          //echo 'foo';
          $my_counter++;
        }
      }
    }
    if ($my_counter > 0)
    {
      return true;
    }
    else{
      return false;
    }
 }

 function get_new_parent($id,$arrayName)
 {

  //echo "*".$id."*";
   for ($i=0; $i < count($arrayName); $i++) { 
    //echo "%".$arrayName[$i]['id'];
      if($arrayName[$i]['id']===$id)
      { echo "*" .$arrayName[$i]['parent'];

        return $arrayName[$i]['parent'];
         }
    }

 }

function hai($arrayName){
 $kk    =count($arrayName);
 for ($i=0; $i <$kk;$i++)
 {
    if($arrayName[$i]['tag']=='ol')
    {
      unset($arrayName[$i]);
    }

 }



 // echo $arrayName[$i]['id'];
 //    echo " ". $arrayName[$i]['parent'];
 //    echo " ". $arrayName[$i]['tag'];
 //    echo " ". $arrayName[$i]['name'];
 //    echo ('<br/>');

print buildNavigation($arrayName,$parent="null");
}

  /**
   *  @Description: recursive function to build list
   *       @Params: --
   *
   *     @returns: --
   */

function buildNavigation($items, $parent = "null")
{
    $hasChildren = false;
    $outputHtml = '<ul>%s</ul>';
    $childrenHtml = '';

    foreach($items as $item)
    {
        if ($item['parent'] == $parent) {
            $hasChildren = true;
            $childrenHtml .= '<li>'.$item['name'];         
            $childrenHtml .= buildNavigation($items, $item['id']);         
            $childrenHtml .= '</li>';           
        }
    }

    // Without children, we do not need the <ul> tag.
    if (!$hasChildren) {
        $outputHtml = '';
    }

    // Returns the HTML
    return sprintf($outputHtml, $childrenHtml);
}

//print buildNavigation($arrayName);












 ?>
Member Avatar for iamthwee

No this is turning into a nightmare my parser is wrong, I'm going have to revisit this.

Hi,
Try this please !

<?php
    $arrayName[0] = array('id' => '2-0', 'parent' => 'null', 'tag' => 'li', 'name' => 'home' );
    $arrayName[1] = array('id' => '1-0', 'parent' => '2-0', 'tag' => 'ol', 'name' => '' );
    $arrayName[2] = array('id' => '0-0', 'parent' => '1-0', 'tag' => 'li', 'name' => 'about' );
    $arrayName[3] = array('id' => '6-0', 'parent' => 'null', 'tag' => 'li', 'name' => 'a' );
    $arrayName[4] = array('id' => '5-0', 'parent' => '6-0', 'tag' => 'ol', 'name' => '' );
    $arrayName[5] = array('id' => '4-0', 'parent' => '5-0', 'tag' => 'li', 'name' => 'b' );
    $arrayName[6] = array('id' => '3-0', 'parent' => '4-0', 'tag' => 'ol', 'name' => '' );
    $arrayName[7] = array('id' => '2-1', 'parent' => '3-0', 'tag' => 'li', 'name' => 'c' );
    $arrayName[8] = array('id' => '1-1', 'parent' => '2-1', 'tag' => 'ol', 'name' => '' );
    $arrayName[9] = array('id' => '0-1', 'parent' => '1-1', 'tag' => 'li', 'name' => 'd' );


/**
* @Description: recursive function to build list
* @Params: --
*
* @returns: --
*/
    function buildNavigation($items, $parent = "null")
    {
        $hasChildren = false;
        $outputHtml = '<ul>%s</ul>'; 
        $childrenHtml = '';
        foreach($items as $item)
        {
            if ($item['parent'] == $parent) 
            {
                $hasChildren = true;
                if($item['name'] != '')
                {
                    $childrenHtml .= '<li>'.$item['name'];
                    $childrenHtml .= '</li>';
                }
                $childrenHtml .= buildNavigation($items, $item['id']); 
            }            
        }
        // Without children, we do not need the <ul> tag.
        if (!$hasChildren) 
        {
            $outputHtml = '';
        }

        // Returns the HTML
        return sprintf($outputHtml, $childrenHtml);
    }



print buildNavigation($arrayName);

?>
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.