technopia
technopia

Reputation: 147

XPath expression to get all preceding siblings UNTIL condition met

Here is my XML:

...
<table></table>
<p class="source"></p>
<p class="notes"></p>
<p class="notes"></p>
<p class="notes"></p>
<p />
<p />
...
<table></table>
<p class="notes"></p>
<p class="notes"></p>
<p />
...

I am trying to write a template which is called for each "<p>" tag. This template will return the index of where this tag lives relative to it's first preceding "<table>" tag. It should only count "<p>" tags that have the attribute "class" equal to "notes".

So for the above example, I'd want the indexes noted in the comments below:

...
<table></table>
<p class="source"></p>
// should return 0 <p class="notes"></p>
// should return 1 <p class="notes"></p>
// should return 2 <p class="notes"></p>
<p />
<p />
...
<table></table>
// should return 0 <p class="notes"></p>
// should return 1 <p class="notes"></p>
<p />
...

Here is what I came up with so far:

 <xsl:template name="PrintTableNumberedNote">
 <xsl:variable name="currentPosition" select="count(preceding-sibling::p[(@class='notes')])"/>
 <xsl:value-of select="$currentPosition"/>.     
 </xsl:template>

I need to add logic to make the count stop at the first occurence of the preceding table, because this is how the results incorrectly look with this template:

...
<table></table>
<p class="source"></p>
// returns 0 <p class="notes"></p>
// returns 1 <p class="notes"></p>
// returns 2 <p class="notes"></p>
<p />
<p />
...
<table></table>
// returns 3 <p class="notes"></p>
// returns 4 <p class="notes"></p>
<p />
...

How do I combine this other criteria to my XPath statement?

Thank you,

Upvotes: 3

Views: 2863

Answers (1)

nwellnhof
nwellnhof

Reputation: 33628

A simple solution is to subtract the p elements before the preceding table:

<xsl:variable name="currentPosition" select="
    count(preceding-sibling::p[@class='notes']) -
    count(preceding-sibling::table/preceding-sibling::p[@class='notes']"/>

If you want the nodeset containing all the p elements between the preceding table and the current node, you could try:

<xsl:variable name="numTables" select="count(preceding-sibling::table)"/>
<xsl:variable name="paragraphs" select="
    preceding-sibling::p[
        @class='notes' and
        count(preceding-sibling::table) = $numTables]"/>

Or, using the variable $currentPosition from above:

<xsl:variable name="paragraphs" select="preceding-sibling::p
    [@class='notes']
    [position() &lt;= $currentPosition]"/>

Also see this similar question.

Upvotes: 2

Related Questions