Reputation: 411
i'm trying to transform a list to a distinct values list using XSLT.
Input:
<object name="obj1"/>
<object name="obj2"/>
<object name="obj1"/>
Desired output:
<object>obj1</object>
<object>obj2</object>
Somebody an idea how to get it done either in XSLT 1.0 or 2.0?
THX
Upvotes: 9
Views: 26696
Reputation: 5022
For XSLT 1.0
objects.xml:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="objects.xsl"?>
<objects>
<object id="id1" name="obj1"/>
<object id="id2" name="obj2"/>
<object id="id3" name="obj1"/>
</objects>
objects.xsl:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="index1" match="*" use="@name" />
<xsl:template match="/">
<objects>
<xsl:for-each select="//*[generate-id() = generate-id(key('index1',@name)[1])]">
<object><xsl:value-of select="@name"/></object>
</xsl:for-each>
</objects>
</xsl:template>
</xsl:stylesheet>
What is happening here:
<xsl:key name="index1" match="*" use="@name" />
you define an index for key()
function named index1
. It must be outside of xsl:template
declaration.match="*"
you define that it is suitable for all elements.use="@name"
you define a search criteria for index1
.key("index1","obj1")
will return an array consists of nodes where attribute @name
equals "obj1"
: [<object name="obj1" id="id1"/>
,<object name="obj1" id="id3"/>
].generate-id()
function that generates unique ID for a given node.<object name="obj1" id="id1"/>
) will return something like "id0xfffffffff6ddca80obj1"
.generate-id()
will return an ID for a current node.xsl:for-each
cycle for all elements //*
with condition that generate-id()
of current node must be equal to generate-id()
of a first node from key('index1',@name)
result. Which means it must be the first node itself.@name
value with xsl:value-of
. Since it happens only for a first element of key('index1',@name)
result, it will be printed only once.Upvotes: 4
Reputation: 167716
Use XSLT 2.0 and
<xsl:for-each select="distinct-values(//object/@name)">
<object><xsl:value-of select="."/></object>
</xsl:for-each>
or
<xsl:for-each-group select="//object" group-by="@name">
<object><xsl:value-of select="current-grouping-key()"/></object>
</xsl:for-each-group>
Upvotes: 19