2

I have lot of trouble with this XPath selction that i use in HtmlAgilityPack.

I want to select all li elements (if they exist) nested in another li witch have a tag with id="menuItem2". This is html sample:

<div id="menu">
  <ul>
    <li><a id="menuItem1"></a></li>
    <li><a id="menuItem2"></a>
       <ul>
          <li><a id="menuSubItem1"></a></li>
          <li><a id="menuSubItem2"></a></li>
       </ul>
    </li>  
    <li><a id="menuItem3"></a></li>
  </ul>
</div>

this is XPath that i been using. When i lose this part /ul/li, it gets me the a tag that I wanted, but i need his descendants... This XPath always returns null.

string xpathExp = "//a[@id='" + parentIdHtml + "']/ul/li";
HtmlNodeCollection liNodes = htmlDoc.DocumentNode.SelectNodes(xpathExp);
Dejan Stuparic
  • 575
  • 2
  • 13
  • 32

4 Answers4

1

The following XPath should work.

string xpathExp = "//li/a[@id='" + parentIdHtml + "']/following-sibling::ul/li";
shriek
  • 5,157
  • 2
  • 36
  • 42
0

Try this for your xpath:

string xpathExp = "//li[a/@id='" + parentIdHtml + "']/ul/li";

The problem is that you were select the a node itself, which has no ul children. You need to select the li node first, and filter on its a child.

yamen
  • 15,390
  • 3
  • 42
  • 52
0

XPath is so messy. You're using the HtmlAgilityPack, you might as well leverage the LINQ.

//find the li -- a *little* complicated with nested Where clauses, but clear enough.
HtmlNode li = htmlDoc.DocumentNode.Descendants("li").Where(n => n.ChildNodes.Where(a => a.Name.Equals("a") && a.Id.Equals("menuItem2", StringComparison.InvariantCultureIgnoreCase)).Count() > 0).FirstOrDefault();
IEnumerable<HtmlNode> liNodes = null;
if (li != null)
{
    //Node found, get all the descendent <li>
    liNodes = li.Descendants("li");
}
Jacob Proffitt
  • 12,664
  • 3
  • 41
  • 47
  • 1
    In this case, I'd say using LINQ here is much messier. I find using XPath whenever available much nicer than writing out a LINQ query, especially when it's a complicated one. – Jeff Mercado May 31 '12 at 03:37
  • You down-voted me because you think XPath is clearer thank Linq? And *particularly* when it's complicated? LOL... – Jacob Proffitt May 31 '12 at 08:31
  • 2
    I didn't downvote you... nor do I see a reason to do so. It's a fine answer and I have no problem with it. I left that comment well before you got downvoted. Get your facts straight LOL... – Jeff Mercado May 31 '12 at 13:31
  • Heh. I wish more people paid attention to the ettiquette of leaving a comment when downvoting. So confusing when they don't. And leaves innocent commenters open to frivolous accusations... :) – Jacob Proffitt May 31 '12 at 15:12
0

From your description I think you want to select the two <li> elements that contain <a> tags with ids menuSubItem1 and menuSubItem2?

If so then this is what you need

//li[a/@id="menuItem2"]//li
Borodin
  • 126,100
  • 9
  • 70
  • 144