Reputation: 163
<a>
<z/>
<b/>
<b/>
<b/>
<c/>
</a>
I want to find the count of 'b' within 'a' when my parsing current node is 'c' using XSLT.
Is it possible to do this using XSLT?
I am not aware of what the element name 'b' would be, i.e. for its preceding sibling.
Upvotes: 1
Views: 1547
Reputation: 29022
I want to find the count of 'b' within 'a' when my parsing current node is 'c'
Let me rephrase that:
you want to count all occurrences of <b>
which are on the same level as <c>
.
This XSLT does the job by calling an <xsl:template>
with a parameter:
the local-name
of the element to be counted (in this case 'b'):
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="//c"> <!-- select the desired target element -->
<xsl:call-template name="count">
<xsl:with-param name="elemName" select="'b'" /> <!-- name of the element -->
</xsl:call-template>
</xsl:template>
<xsl:template name="count"> <!-- count all matching elements before and after -->
<xsl:param name="elemName" />
<xsl:value-of select="count(preceding-sibling::*[local-name() = $elemName]) + count(following-sibling::*[local-name() = $elemName])" />
</xsl:template>
</xsl:stylesheet>
In the case of your example the output simply is:
3
Upvotes: 0
Reputation: 30971
Use xsl:number
. It prints out the numer of the current element, formatted as required.
There are various options concerning how to perform the numeration, e.g. multi-level or alphabetic one.
Actually it is quite a powerful tool.
Upvotes: 1
Reputation: 70618
If you are positioned on c
tag, or whatever the element is actually called, then to get the count of the preceding siblings, you would do this...
<xsl:value-of select="count(preceding-sibling::*)" />
EDIT: In answer to your comment, if you don't want to count all siblings, but only the count of the immediately preceding one, and the ones with the same name before that, you could try this...
<xsl:value-of select="count(preceding-sibling::*[name() = name(current()/preceding-sibling::*[1])])" />
This would not work though in the case you had multiple c
nodes under one parent...
<a>
<z/>
<b/>
<b/>
<b/>
<c/>
<z/>
<b/>
<c/>
</a>
In this case, you could define a key like this, to group elements by the unique id of the first following element with a different name:
<xsl:key name="keyc" match="*" use="generate-id(following-sibling::*[name() != name(current())][1])" />
Then you can get the count like so:
<xsl:value-of select="count(key('keyc', generate-id()))" />
Here are the three options in action....
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:key name="keyc" match="*" use="generate-id(following-sibling::*[name() != name(current())][1])" />
<xsl:template match="c">
<c>
<example1>
<xsl:value-of select="count(preceding-sibling::*)" />
</example1>
<example2>
<xsl:value-of select="count(preceding-sibling::*[name() = name(current()/preceding-sibling::*[1])])" />
</example2>
<example3>
<xsl:value-of select="count(key('keyc', generate-id()))" />
</example3>
</c>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Upvotes: 3