I've written some XSLT that uses one XML document to filter another. Now I'd like to number my output elements using position()
, but my filtering condition is not built in to my <xsl:for-each>
, so position()
gives me results with numbering gaps. How do I get rid of the gaps?
<xsl:variable name="Astring">
<a><b>10</b><b>20</b><b>30</b></a>
</xsl:variable>
<xsl:variable name="A" select="msxml:node-set($Astring)" />
<xsl:variable name="Bstring">
<c><d>20</d><d>30</d></c>
</xsl:variable>
<xsl:variable name="B" select="msxml:node-set($Bstring)" />
<e>
<xsl:for-each select="$A/a/b">
<xsl:variable name="matchvalue" select="text()" />
<xsl:if test="count($B/c/d[text() = $matchvalue]) > 0">
<xsl:element name="f">
<xsl:attribute name="i">
<xsl:value-of select="position()" />
</xsl:attribute>
<xsl:copy-of select="text()" />
</xsl:element>
</xsl:if>
</xsl:for-each>
</e>
Here's the result:
<e>
<f i="2">20</f>
<f i="3">30</f>
</e>
...but I want this:
<e>
<f i="1">20</f>
<f i="2">30</f>
</e>
Is there any way to incorporate the above <xsl:if>
filtering test inside the <xsl:for-each>
select
attribute?
Note: I've seen this question re: filtering and this one re: counters, but the former doesn't number its results and the latter uses position().
I'm unsure why people always want to use
<xsl:for-each>
when<xsl:apply-templates>
is clearly the better alternative.Ok, this is rhetorical. I know why this is:
<xsl:for-each>
seems to be easier. But it isn't — the following two templates replace your entire for-each construct:Output:
Well, I cheated a bit. You can condense the
<xsl:for-each>
version to this:Still, it lacks the lightness of the
<xsl:apply-templates>
variant, IMHO.Is there any particular reason why you can't include your condition inside the for-each loop?
I tested this out in Visual Studio and it works fine for this example.
This was the output: