0

I have a multi level <ul><li> menu structure. I am trying to get the top level LI that has a descendant LI with a class of "current-menu-line".

My HTML

<ul id="menu1" class="nav">
  <li class="menu-item dorment-menu-item"><a href="http://localhost/index.html">welcome</a></li>
  <li class="menu-item dorment-menu-item"><a href="http://localhost/evidence.html">evidence</a></li>
  <li class="menu-item dorment-menu-item"><a href="http://localhost/network.html">network</a></li>
  <li class="menu-item dorment-menu-item"><a href="http://localhost/multi-page-pc-22.html">Multi page</a>
    <ul class="subnav">
      <li class="menu-item current-menu-line"><a href="http://localhost/new-page-1-pg-47.html">page 1</a></li>
    </ul>
  </li>
</ul>

I have tried a number of xPath queries to get the topmost <li> that has the descendant with no success

$query = '//li[contains(@class, "current-menu-line")]'; // this one works ... makes sure LI.current-menu-line can be found
$query = '/ul/li[li[contains(@class, "current-menu-line")]]'; // returns 0 rows
$query = '/ul/li[//li[contains(@class, "current-menu-line")]]'; // returns 0 rows
$query = '/ul/li[descendant::li[contains(@class, "current-menu-line")]]'; // returns 0 rows

// added after examining "Select elements which has certain descendent using Xpath"

$query = '/ul/li[.//li[contains(@class, "current-menu-line")]]' ; // returns 0 nodes
$query = "/ul/li[descendant::li[@class, 'current-menu-line')]]"; // invalid query

Is someone able to tell me the correct query to get the correct LI ?

Cheers

5
  • simple hack, assuming that the target li is always two above the one with the class: //li[contains(@class, 'current-menu-line')]/../.. Commented Jul 23, 2013 at 19:18
  • Good answer, unfortunately I cannot guarantee that the UL structure is only 2 deep Commented Jul 23, 2013 at 19:34
  • possible duplicate of Select elements which has certain descendent using Xpath Commented Jul 23, 2013 at 19:38
  • I looked there and tried the queries, they didn't work. See results in the edited question. Commented Jul 23, 2013 at 19:58
  • For others with the same problem, my loop solution was $query = '//li[contains(@class, "current-menu-line")]'; // returns 1 node $entries = $xpath->query($query); $entry = $entries->item(0) ; // we know that the parent of an LI is a UL while ( $entry->parentNode->hasAttribute('class') && ! preg_match('/\bnav\b/', $entry->parentNode->getAttribute('class')) ) { // the while condition was not met so advance back up the tree to the previous LI $entry = $entry->parentNode->parentNode ; } Sorry about the lack of formatting Commented Jul 25, 2013 at 1:20

1 Answer 1

1

This selection should fit your description:

 /ul/li[.//li[contains(@class, 'current-menu-line')]]

I see that you tried this already and it did not return any nodes for you, but I suspect there might be a difference in the XML-snipped that you provided to the actual XML that you use. I verified the XPath using an online XPath evaluator and it returns the correct result even if the nested structure is more than two levels below.

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

1 Comment

Thanks for that tfoo. As you said, I had tried it and it hadn't worked. I copy/pasted directly from your suggestion but it still didn't work. This suggests it's a problem with PHP rather than DOMXpath. The exact code I'm using is

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.