Home | Blog | Software | Reviews and Features | Forum | Help | Donate | About us
topbanner_forum
  *

avatar image

Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length
  • December 04, 2016, 12:25:06 PM
  • Proudly celebrating 10 years online.
  • Donate now to become a lifetime supporting member of the site and get a non-expiring license key for all of our programs.
  • donate

Author Topic: PHP5 driving me insane! removeChild() bug?  (Read 3225 times)

Ampa

  • Charter Member
  • Joined in 2005
  • ***
  • Posts: 592
  • I am cute ;)
    • View Profile
    • MonkeyDash - 2 Player strategy boardgame
    • Donate to Member
PHP5 driving me insane! removeChild() bug?
« on: January 14, 2008, 08:29:40 PM »
1st: I am NOT a PHP expert. I struggle. I read a lot of help and tutorials. I understand some of them!

2nd: I found a PHP driven menu system called EasyNav - that was the easy bit.. things go downhill from this point!

I like the way that PHP is used to rewrite the site navigation, specifically removing nested menu items, and applying ID and CLASS tags to the menu to facilitate easy styling.

BUT the original script is written for PHP4 and my host uses PHP5. No problem, I thought, I'll rewrite the bits of the script that I need, and learn a lot about PHP along the way.

Generally I have got things working, but there is a bug in the code somewhere...

In one section I loop through all the UL elements in the DOM, checking to see whether their parent nodes are LI elements. If they are then the UL is a nested list, and so, unless it is the one containing the current page, should be removed from the menu.

Code: PHP [Select]
  1. $HTMLDOM = new DOMDocument();                           //Create a new DOMDocument.
  2. $HTMLDOM->loadHTML($NavHTML);                           //Convert $NavHTML to a tree of DOM objects.
  3. $ULs = $HTMLDOM->getElementsByTagname("ul");            //Get a NodeList of the <ul> elements in the document.
  4. foreach($ULs as $CurrentUL)                                     //For each <ul>...
  5. {
  6.         $ULParent=$CurrentUL->parentNode;                       //Get its parent.
  7.         if ($ULParent->nodeName=='li')                          //If parent is an <li>, then this is a nested list...
  8.         {
  9.                 if($ULParent->getElementsByTagName('strong')->item(0)==NULL)    //If the nested list does NOT contain current page.
  10.                 {
  11.                         $ULParent->removeChild($CurrentUL);     //Remove the child node. (ie the nested list).
  12.                 }
  13.         }
  14. }

To test it I run the loop on the following navigation structure...

Code: HTML [Select]
  1. <ul id="NavRoot">
  2.   <li><a href="index.php">A no_kids</a></li>
  3.   <li><a href="B.php">B 2_kids</a>
  4.     <ul id="Bsub">
  5.       <li><a href="B1.php">B.1</a></li>    
  6.       <li><a href="B2.php">B.2</a></li>    
  7.     </ul>
  8.   </li>
  9.   <li><a href="C.php">C 2_kids</a>
  10.     <ul id="Csub">
  11.       <li><a href="C1.php">C.1</a></li>    
  12.       <li><a href="C2.php">C.2</a></li>    
  13.     </ul>
  14.   </li>
  15.   <li><a href="D.php">D 2_kids</a>
  16.     <ul id="Dsub">
  17.       <li><a href="D1.php">D.1</a></li>    
  18.       <li><a href="D2.php">D.2</a></li>    
  19.     </ul>
  20.   </li>
  21.   <li><a href="E.php">E no_kids</a></li>
  22. </ul>

The current page is index.php, so ALL the sub-menus should be removed; but the actual output is...

A no_kids
B 2_kids
C 2_kids
C.1
C.2
D 2_kids
E no_kids

ie. sub-menus B and D are removed but C is not!

If I watch what is happening in the code, the foreach loop skips the iteration for C. If I comment out the removeNode() command, then the loop works correctly.

Does anyone have any idea why the removeNode() command is causing my loop to jump?

f0dder

  • Charter Honorary Member
  • Joined in 2005
  • ***
  • Posts: 9,029
  • [Well, THAT escalated quickly!]
    • View Profile
    • f0dder's place
    • Read more about this member.
    • Donate to Member
Re: PHP5 driving me insane! removeChild() bug?
« Reply #1 on: January 14, 2008, 08:50:36 PM »
Hm, perhaps something along the lines of iterator invalidation - I don't know what PHP does, but at least in C++ when you're iterating over container elements, for most container types it's unsafe to remove items from the container. Probably not the problem here, but if it is the problem, you'll probably end up having to restructure the code; instead of removing items from the actual list, change it so you build a copy (excluding the items you don't want), and then "activate" that copy...
- carpe noctem

Ampa

  • Charter Member
  • Joined in 2005
  • ***
  • Posts: 592
  • I am cute ;)
    • View Profile
    • MonkeyDash - 2 Player strategy boardgame
    • Donate to Member
Re: PHP5 driving me insane! removeChild() bug?
« Reply #2 on: January 15, 2008, 12:34:40 PM »
Thanks F0dder, I think you are right...

When I remove the child node, the length of the FOREACH loop changes, so I need to replace it with a standard FOR loop, and decrement the loop counter if a node is removed.

UPDATE: Tried it. It works :)

Thanks again