I would like to get the distinct values inside of a for loop, or within some group. Since the xsl:key can only be declared at the top level, how would I be able to make a xsl:key for each group? In the example below, the group would be the most outer fruit tags. Note that there's also a xsl:sort. If there is a way to accomplish this by just xpaths (preceding-sibling), I would love to know this solution as well. I'm not sure if I would need to use the Muenchian method to accomplish this, but this is what I have:
Input.xml
<root>
<fruits>
<fruit>
<fruit id="2">
<banana><taste>Yummy</taste></banana>
<banana><taste>Disgusting</taste></banana>
</fruit>
<fruit id="1">
<banana><taste>Eh</taste></banana>
<banana><taste>Disgusting</taste></banana>
</fruit>
</fruit>
<fruit>
<fruit id="2">
<banana><taste>Yummy</taste></banana>
<banana><taste>Disgusting</taste></banana>
</fruit>
<fruit id="1">
<banana><taste>Amazing</taste></banana>
<banana><taste>Disgusting</taste></banana>
</fruit>
</fruit>
</fruits>
</root>
Transform.xsl
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:key name="taste" use="." match="taste" />
<xsl:template match="root">
<xsl:apply-templates select="fruits" />
</xsl:template>
<xsl:template match="fruits">
<xsl:element name="newFruits">
<xsl:call-template name="test" />
</xsl:element>
</xsl:template>
<xsl:template name="test">
<xsl:for-each select="fruit">
<xsl:sort select="fruit/@id" />
<xsl:element name="newFruit">
<!-- xsl:for-each select="fruit/banana/taste[not(.=preceding::taste)]/.." /> -->
<xsl:for-each select="fruit/banana/taste[generate-id() = generate-id(key('taste',.)[1])]/..">
<xsl:element name="fruit">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Output (comments in the output is the desired tags that should appear)
<?xml version="1.0" encoding="UTF-8"?>
<newFruits>
<newFruit>
<fruit>Yummy</fruit>
<fruit>Disgusting</fruit>
<fruit>Eh</fruit>
</newFruit>
<newFruit>
<!-- <fruit>Yummy</fruit> -->
<!-- <fruit>Disgusting</fruit> -->
<fruit>Amazing</fruit>
</newFruit>
</newFruits>
The issue is that you want your
tasteelements to be distinct per each top-levelfruitelement. Your current grouping is getting the distinct elements for the whole document.If you can't update to XSLT 2.0 then shed a tear, as you have to then use a concatenated key in XSLT 1.0, to include a unique identifier for the relevant
fruitelement, which can be achieved by usinggenerate-id()Then, in your "test" template, define a variable to hold the id for the relevant fruit...
And your expression to get the distinct tastes becomes this...
Try this XSLT
Note, you don't really need the first template, and I can't see the point of a named template, so you can simplify the above XSLT to this...