XPath "previously following siblings"

html-agility-pack xpath


I'm trying to select elements (a) with XPath 1.0 (or possibly could be with Regex) that are following siblings of particular element (b) but only preceed another b element.

<img>&nbsp;&nbsp;<a href="/first-href">First Href</a> - 19:30<br>
<img>&nbsp;&nbsp;<a href="/second-href">Second Href</a> - 19:30<br>
<img>&nbsp;&nbsp;<a href="/third-href">Third Href</a> - 19:30<br>

I tried to make the sample as close to real world as possible. So in this scenario when I'm at element


I need to select

<a href="/first-href">First Href</a> 

and when I'm at


I need to select

<a href="/second-href">Second Href</a> 
<a href="/third-href">Third Href</a>

Any idea how to achieve that? Thank you!

2/17/2010 6:39:44 PM

Accepted Answer

Dynamically create this XPath:


where 'xxxx' is the replaced with the text of the current <b>.

This is assuming that all the elements actually are siblings. If they are not, you can try to work with the preceding and following axes, or you write a more specific XPath that better resembles document structure.

In XSLT you could also use:

  generate-id(preceding-sibling::b[1]) = generate-id(current())
2/17/2010 1:43:37 PM

Popular Answer

Here is a solution which is just a single XPath expression.

Using the Kaysian formula for intersection of two nodesets $ns1 and $ns2:

  $ns1[count(. | $ns2) = count($ns2)]

We simply substitute $ns1 with the nodeset of <a> siblings that follow the current <b> node, and we substitute $ns2 with the nodeset of <a> siblings that precede the next <b> node.

Here is a complete transformation that uses this:

<xsl:stylesheet version="1.0"
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

  <xsl:template match="/">
   <xsl:apply-templates select="*/b"/>

  <xsl:template match="b">
    At: <xsl:value-of select="."/>

    <xsl:variable name="vNextB" select="following-sibling::b[1]"/>

    <xsl:variable name="vA-sAfterCurrentB" select="following-sibling::a"/>

    <xsl:variable name="vA-sBeforeNextB" select=

    <xsl:copy-of select=
              [count(.| $vA-sBeforeNextB)

When this transformation is applied on the following XML document:

    <br />&#xA0;&#xA0;
    <a href="/first-href">First Href</a> - 19:30
    <br />
    <br />
    <a href="/second-href">Second Href</a> - 19:30
    <br />
    <a href="/third-href">Third Href</a> - 19:30
    <br />

the correct result is produced:

   At: First <a href="/first-href">First Href</a>
    At: Second <a href="/second-href">Second Href</a>
<a href="/third-href">Third Href</a>

Related Questions


Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow