0

I have to create a menu from a list with possible sub-lists. From a simple I want to create a compatible bootstrap menu So from a code like this:

<ul>
  <li>Link 1</li>
  <li>Link 2
    <ul>
      <li>Sublink A</li>
      <li>Sublink B</li>
    </ul>
  </li>
  <li>Link 3
    <ul>
      <li>Sublink C</li>
    </ul>
  </li>
</ul>

I'll have to create this:

array(
  [0] => array(
    [id]       => 1,
    [nome]  => 'Link 1',
    [parent] => NULL,
  ),
  [1] => array(
    [id]       => 2,
    [nome]  => 'Link 2',
    [parent] => NULL,
  ),
  [2] => array(
    [id]       => 3,
    [nome]  => 'Sublink A',
    [parent] => 2
  ),
  [3] => array(
    [id]       => 4,
    [nome]  => 'Sublink B',
    [parent] => 2
  ),
  [4] => array(
    [id]       => 5,
    [nome]  => 'Link 3',
    [parent] => NULL
  ),
  [5] => array(
    [id]       => 6,
    [nome]  => 'Sublink C',
    [parent] => 3
  )
)  

And finally, get back this one:

<ul class="nav navbar-nav">
  <li><a class="primary" href="link_1.html">Link 1</a></li>
  <li class="dropdown">
    <a href="#" class="primary dropdown-toggle" data-toggle="dropdown">Link 2</a>
    <ul class="dropdown-menu">
      <li><a href="sublink_a.html">Sublink A</a></li>
      <li><a href="sublink_b.html">Sublink B</a></li>
    </ul>
  </li>
  <li class="dropdown">
    <a href="#" class="primary dropdown-toggle" data-toggle="dropdown">Link 3</a>
    <ul class="dropdown-menu">
      <li><a href="sublink_c.html">Sublink C</a></li>
    </ul>
  </li>
</ul>

Conditions are: if

  • has children has href="#", add class dropdown-toogle and data-toggle="dropdown"; child has class "dropdown-menu"; if
  • hasn't parent add class "primary" to

    I use this code, but it's only for a simple list, not nested lists.

    <?php
    $currentPage = "";
    $contents = "<ul>
      <li>Link 1</li>
      <li>Link 2</li>
      <li>Link 3</li>
    </ul>";
    
    // remove width, height, style
    $contents = preg_replace('/(width|height|style|target)="[^"]+"/i', "", $contents);
    // remove spaces form li
    $contents = str_replace(array('<li >',' <li >'),"<li>",$contents);
    // remove ul/ol tag and tabs
    $contents = str_replace(array('\t','<ul>','<ul >','</ul>','<ol>','<ol >','</ol>'),"",$contents);
    $arrNavTopList = explode("\n",trim($contents));
    echo "<h4>Array:</h4>\n";
    print_r($arrNavTopList);
    echo "<hr>\n<h4>List:</h4>\n";
    $totNavTopList = count($arrNavTopList);
    if($totNavTopList>0){
      echo '<ul class="nav navbar-nav">'."\n";
      $countNtL=1;
      foreach($arrNavTopList as $pagename) {
        $pagename = str_replace("\t","",$pagename);
        preg_match_all("(<li>(.*?)</li>)", $pagename, $arrLinkList);
        $linktopage = $arrLinkList[1][0];
        if(
          strtolower($linktopage)==strtolower(str_replace("_"," ",$currentPage)) ||
          strtolower($linktopage)=="home" && !(strpos($currentPage,"^")===FALSE)
        ) {
          $active=' class="active"';
        } else {
          $active='';
        }
        echo '<li'.$active.'>';
        if (strstr($linktopage,"http") || strstr($linktopage,"target")) {
          $linktopage = preg_replace('/(style|target)="[^"]+"/i', "", $linktopage);
          $linktopage = str_replace('<a','<a rel="external nofollow" class="_blank"',$linktopage);
          echo $linktopage;
        } else {
          if(strtolower($linktopage)=="home" || strtolower($linktopage)=="home page") {
            echo '<a href="/">'.htmlentities($linktopage).'</a>';
          } else {
            echo '<a href="'.str_replace(" ","_",strtolower($linktopage)).'">'.htmlentities($linktopage).'</a>';
          }
        }
        echo '</li>'."\n";
        $countNtL++;
      }
      echo '</ul>'."\n";
    }
    ?>
    
  • 4
    • 1
      as @Soundz mentionned you have to work more before posting that kind of question, there are tons of ways to implement what you want. I would use nested foreach with preg_match or something like that. Commented Oct 11, 2013 at 17:39
    • @Johnride what a nice way to express for what I only have harsh words for. Topic: How about a object which assembles it? Commented Oct 11, 2013 at 17:45
    • Try it at least, dont be lazy, here nobody write a complete code for anybody, somehow I would use recursivity. Commented Oct 11, 2013 at 18:14
    • I wrote a code that changes a simple list in a list with links, but I need something different. That's why I asked here without posting any kind of code. I do not have a code that does the extra step and did not want to write too much about the request. Commented Oct 12, 2013 at 8:54

    1 Answer 1

    0
    <?php
    /**
     * Traverse an elements children and collect those nodes that
     * have the tagname specified in $tagName. Non-recursive
     *
     * @param DOMElement $element
     * @param string $tagName
     * @return array
     */
    
     //from: https://stackoverflow.com/a/3049677/1596547
    
    function getImmediateChildrenByTagName(DOMElement $element, $tagName)
    {
        $result = array();
        foreach($element->childNodes as $child)
        {
            if($child instanceof DOMElement && $child->tagName == $tagName)
            {
                $result[] = $child;
            }
        }
        return $result;
    }
    
    $doc = new DOMDocument();
    $doc->loadHTML("<ul>
      <li>Link 1</li>
      <li>Link 2
        <ul>
          <li>Sublink A</li>
          <li>Sublink B</li>
        </ul>
      </li>
      <li>Link 3
        <ul>
          <li>Sublink C</li>
        </ul>
      </li>
    </ul>");
    
    //from: https://stackoverflow.com/a/6953808/1596547
    # remove <!DOCTYPE 
    $doc->removeChild($doc->firstChild);            
    
    # remove <html><body></body></html> 
    $doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild);
    
    $elements = $doc->getElementsByTagName('ul');
    $parentitems = getImmediateChildrenByTagName($elements->item(0),'li');
    $elements->item(0)->setAttribute ('class' , 'nav navbar-nav');
    foreach ($parentitems as $parentitem)
    {
        if($parentitem->childNodes->length > 1) {
    
            $parentitem->setAttribute ('class' , 'dropdown' );
            $link = $doc->createElement('a',$parentitem->childNodes->item(0)->nodeValue);
            $link->setAttribute ('class' , 'primary dropdown-toggle' );
            $link->setAttribute ('href' , '#');
            $link->setAttribute ('data-toggle','dropdown');
            //$parentitem->nodeValue = null; 
            $old = $parentitem->childNodes->item(0);
            $parentitem->replaceChild($link,$old);
    
            $parentitem->childNodes->item(1)->setAttribute ('class' , 'dropdown-menu' );
            $submenuitems = getImmediateChildrenByTagName($parentitem->childNodes->item(1),'li');
    
            foreach($submenuitems as $submenuitem)
            {
                $link = $doc->createElement('a',$submenuitem->nodeValue);
                $link->setAttribute ('href' , $submenuitem->childNodes->item(0)->nodeValue.'.html');
                $submenuitem->nodeValue = null; 
                $submenuitem->appendChild($link);
            }   
    
    
        }
        else 
        {
            $link = $doc->createElement('a',$parentitem->nodeValue);
            $link->setAttribute ('class' , 'primary' );
            $link->setAttribute ('href' , $parentitem->childNodes->item(0)->nodeValue.'.html');
            $parentitem->nodeValue = null; 
            $parentitem->appendChild($link);
        }
    
    
    }   
    
    echo $doc->saveHTML();
    

    other answers used:

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

    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.