I'm using XSLT to try to grab content from an html page. I want to select all the <p> tags but exclude all the <li> tags. There is one page where the li tags are not within any of the p tags. For this page, how can I select all p elements but leave out all li elements? I'm trying to use the Xpath exclusion notation, e.g. [not()]

Dani AI

Generated

Both answers were on the right track. was pointing out that a broad descendant search will pick up every paragraph; solved the immediate problem by narrowing the path to the page content container. If the goal is "take every <p> except those that are inside an <li>", a predicate that rejects paragraphs with an li ancestor is the clearest approach.

Select paragraphs that do not have an li ancestor:

p[not(ancestor::li)]

In XSLT you can apply that directly in a template match:

<xsl:template match="p[not(ancestor::li)]">
  <!-- process paragraphs that are not inside list items -->
</xsl:template>

Notes and caveats:

  • If the source is HTML (not well-formed XML) run it through an HTML-to-XHTML converter or an HTML parser (for example, HTML Tidy) before applying XPath/XSLT.
  • If the document uses the XHTML namespace, element names must be namespace-qualified in XPath (bind a prefix and use it for p and li).
  • For very large documents the ancestor:: axis is fine in typical cases, but if performance becomes a concern, restrict the search to the known content subtree rather than the whole document.

For XPath reference see MDN — XPath. For converting messy HTML to XHTML see HTML Tidy.

Recommended Answers

All 2 Replies

Why doesn't //p work?

You're problem isn't very well described. If you want a clear answer, please give is a stripped down sample document that we can see and use to see your problem. Along with what your desired result set looks like. Do something like this user does in this thread.

http://www.daniweb.com/forums/thread326036.html

OK, sorry about the bad description. I just needed to play with Xpath a bit more before I realized how it was working. The solution I used happened to be:

//div[@id='text']/p

Which simply excludes everything but the p elements in the defined path. No need for an exclusion expression.

Thank you much!

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.