Reputation: 71
I want to remove the duplicate values from the concatenated string.
Input is:
<?xml version="1.0" encoding="ISO-8859-1"?>
<QL>
<QITEM>
<SERIAL>123</SERIAL>
<PROD_NAME>User/Device</PROD_NAME>
</QITEM>
<QITEM>
<SERIAL>123</SERIAL>
<PROD_NAME>User/Dev</PROD_NAME>
</QITEM>
<QITEM>
<SERIAL>123</SERIAL>
<PROD_NAME>User/Device</PROD_NAME>
</QITEM>
<QITEM>
<SERIAL>1234</SERIAL>
<PROD_NAME>45 Mbps</PROD_NAME>
</QITEM>
</QL>
<QL>
<QITEM>
<SERIAL>123</SERIAL>
<PROD_NAME>User/Device</PROD_NAME>
</QITEM>
<QITEM>
<SERIAL>123</SERIAL>
<PROD_NAME>User/Dev</PROD_NAME>
</QITEM>
<QITEM>
<SERIAL>123</SERIAL>
<PROD_NAME>User/Device</PROD_NAME>
</QITEM>
<QITEM>
<SERIAL>1234</SERIAL>
<PROD_NAME>45 Mbps</PROD_NAME>
</QITEM>
</QL>
I want to concatenate the values and the output should be like:
<Result>
<SERIAL>123,1234</SERIAL>
<PROD_NAME>User/Dev,User/Device,45 Mbps</PROD_NAME>
</Result>
<Result>
<SERIAL>123,1234</SERIAL>
<PROD_NAME>User/Dev,User/Device,45 Mbps</PROD_NAME>
</Result>
So far, I have tried to achieve this with the following template:
<xsl:template name="join">
<xsl:param name="list"/>
<xsl:param name="separator"/>
<xsl:for-each select="$list">
<xsl:value-of select="."/>
<xsl:if test="position() != last()">
<xsl:value-of select="$separator"/>
</xsl:if>
</xsl:for-each>
</xsl:template>
This is giving the values separated by comma.
But I want to get the unique values.
Upvotes: 0
Views: 1131
Reputation: 52858
Unique/distinct values in pure XSLT 1.0 is best achieved by using the Muenchian Method of grouping.
In the example below, we create an xsl:key
for each one of the items we want to have a group of.
For example, the key serial
is a group of all SERIAL
elements using the value of itself as the grouping key.
Then we loop over each group (xsl:for-each
) and only select the first occurrence of that group.
Full example...
XML Input
<QL>
<QITEM>
<SERIAL>123</SERIAL>
<PROD_NAME>User/Device</PROD_NAME>
</QITEM>
<QITEM>
<SERIAL>123</SERIAL>
<PROD_NAME>User/Dev</PROD_NAME>
</QITEM>
<QITEM>
<SERIAL>123</SERIAL>
<PROD_NAME>User/Device</PROD_NAME>
</QITEM>
<QITEM>
<SERIAL>1234</SERIAL>
<PROD_NAME>45 Mbps</PROD_NAME>
</QITEM>
</QL>
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="serial" match="SERIAL" use="."/>
<xsl:key name="prodname" match="PROD_NAME" use="."/>
<xsl:template match="/*">
<Result>
<SERIAL>
<xsl:for-each select="QITEM/SERIAL[count(.|key('serial',.)[1])=1]">
<xsl:if test="position() > 1">,</xsl:if>
<xsl:value-of select="."/>
</xsl:for-each>
</SERIAL>
<PROD_NAME>
<xsl:for-each select="QITEM/PROD_NAME[count(.|key('prodname',.)[1])=1]">
<xsl:if test="position() > 1">,</xsl:if>
<xsl:value-of select="."/>
</xsl:for-each>
</PROD_NAME>
</Result>
</xsl:template>
</xsl:stylesheet>
XML Output
<Result>
<SERIAL>123,1234</SERIAL>
<PROD_NAME>User/Device,User/Dev,45 Mbps</PROD_NAME>
</Result>
UPDATE
I'm not sure I completely understand your update, but what I think you can do is create a compound key using the generated id of the ancestor QL
.
XML Input (Wrapped in doc
to make it well-formed.)
<doc>
<QL>
<QITEM>
<SERIAL>123</SERIAL>
<PROD_NAME>User/Device</PROD_NAME>
</QITEM>
<QITEM>
<SERIAL>123</SERIAL>
<PROD_NAME>User/Dev</PROD_NAME>
</QITEM>
<QITEM>
<SERIAL>123</SERIAL>
<PROD_NAME>User/Device</PROD_NAME>
</QITEM>
<QITEM>
<SERIAL>1234</SERIAL>
<PROD_NAME>45 Mbps</PROD_NAME>
</QITEM>
</QL>
<QL>
<QITEM>
<SERIAL>123</SERIAL>
<PROD_NAME>User/Device</PROD_NAME>
</QITEM>
<QITEM>
<SERIAL>123</SERIAL>
<PROD_NAME>User/Dev</PROD_NAME>
</QITEM>
<QITEM>
<SERIAL>123</SERIAL>
<PROD_NAME>User/Device</PROD_NAME>
</QITEM>
<QITEM>
<SERIAL>1234</SERIAL>
<PROD_NAME>45 Mbps</PROD_NAME>
</QITEM>
</QL>
</doc>
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="serial" match="SERIAL" use="concat(generate-id(ancestor::QL),'|',.)"/>
<xsl:key name="prodname" match="PROD_NAME" use="concat(generate-id(ancestor::QL),'|',.)"/>
<xsl:template match="QL">
<Result>
<SERIAL>
<xsl:for-each select="QITEM/SERIAL[count(.|key('serial',concat(generate-id(ancestor::QL),'|',.))[1])=1]">
<xsl:if test="position() > 1">,</xsl:if>
<xsl:value-of select="."/>
</xsl:for-each>
</SERIAL>
<PROD_NAME>
<xsl:for-each select="QITEM/PROD_NAME[count(.|key('prodname',concat(generate-id(ancestor::QL),'|',.))[1])=1]">
<xsl:if test="position() > 1">,</xsl:if>
<xsl:value-of select="."/>
</xsl:for-each>
</PROD_NAME>
</Result>
</xsl:template>
</xsl:stylesheet>
XML Output
<Result>
<SERIAL>123,1234</SERIAL>
<PROD_NAME>User/Device,User/Dev,45 Mbps</PROD_NAME>
</Result>
<Result>
<SERIAL>123,1234</SERIAL>
<PROD_NAME>User/Device,User/Dev,45 Mbps</PROD_NAME>
</Result>
Upvotes: 1