Re: [xsl] Grouping elements that have at least one common value

Subject: Re: [xsl] Grouping elements that have at least one common value
From: "Martin Honnen martin.honnen@xxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Fri, 16 Jun 2023 11:51:34 -0000
On 6/16/2023 1:09 PM, Matthieu Ricaud-Dussarget ricaudm@xxxxxxxxx wrote:
>
> Hi all,
>
> I need to group elements that have at least one common valueB :
>
> <FORMS>
>
> <!--CASE 1-->
>
> <GRCHOIX CODE="grchoix-1">
>
> <CHOIX CODE="choix-1"/>
>
> <CHOIX CODE="choix-2"/>
>
> </GRCHOIX>
>
> <GRCHOIX CODE="grchoix-2">
>
> <CHOIX CODE="choix-1"/>
>
> <CHOIX CODE="choix-2"/>
>
> <CHOIX CODE="choix-3"/>
>
> </GRCHOIX>
>
> <GRCHOIX CODE="grchoix-3">
>
> <CHOIX CODE="choix-2"/>
>
> <CHOIX CODE="choix-3"/>
>
> <CHOIX CODE="choix-4"/>
>
> </GRCHOIX>
>
> <!--CASE 2-->
>
> <GRCHOIX CODE="grchoix-A">
>
> <CHOIX CODE="choix-a"/>
>
> <CHOIX CODE="choix-b"/>
>
> </GRCHOIX>
>
> <GRCHOIX CODE="grchoix-B">
>
> <CHOIX CODE="choix-b"/>
>
> <CHOIX CODE="choix-c"/>
>
> </GRCHOIX>
>
> <GRCHOIX CODE="grchoix-C">
>
> <CHOIX CODE="choix-d"/>
>
> <CHOIX CODE="choix-e"/>
>
> </GRCHOIX>
>
> <GRCHOIX CODE="grchoix-D">
>
> <CHOIX CODE="choix-c"/>
>
> <CHOIX CODE="choix-d"/>
>
> </GRCHOIX>
>
> </FORMS>
>
> * grchoix-1 and grchoix-2 have 2 common valuesB : choix-1, choix-2 b
> they must belong the same group
>
> * grchoix-2 and grchoix-3 have 2 common valuesB : choix-2, choix-3 b
> they must belong the same group
>
> b At the end : grchoix-1, grchoix-2 and grchoix-3 must belong the same
> group
>
> * grchoix-A and grchoix-B have 1 common valueB choix-b b they must
> belong the same group
>
> * grchoix-B and grchoix-C have 0 common values
>
> * but as grchoix-D have
>
> - 1 common value (choix-c) with grchoix-B
>
> - 1 one common value (choix-d) with grchoix-C
>
> Then grchoix-B and grchoix-C must also belong the same GROUP
>
> b At the end : grchoix-A, grchoix-B, grchoix-C and grchoix-D must
> belong the same group
>
> The expected XML output is 2 Groups :
>
> <FORMS>
>
> <!--CASE 1-->
>
> <GROUP>
>
> <GRCHOIX CODE="grchoix-1">
>
> <CHOIX CODE="choix-1"/>
>
> <CHOIX CODE="choix-2"/>
>
> </GRCHOIX>
>
> <GRCHOIX CODE="grchoix-2">
>
> <CHOIX CODE="choix-1"/>
>
> <CHOIX CODE="choix-2"/>
>
> <CHOIX CODE="choix-3"/>
>
> </GRCHOIX>
>
> <GRCHOIX CODE="grchoix-3">
>
> <CHOIX CODE="choix-2"/>
>
> <CHOIX CODE="choix-3"/>
>
> <CHOIX CODE="choix-4"/>
>
> </GRCHOIX>
>
> </GROUP>
>
> <!--CASE 2-->
>
> <GROUP>
>
> <GRCHOIX CODE="grchoix-A">
>
> <CHOIX CODE="choix-a"/>
>
> <CHOIX CODE="choix-b"/>
>
> </GRCHOIX>
>
> <GRCHOIX CODE="grchoix-B">
>
> <CHOIX CODE="choix-b"/>
>
> <CHOIX CODE="choix-c"/>
>
> </GRCHOIX>
>
> <GRCHOIX CODE="grchoix-C">
>
> <CHOIX CODE="choix-d"/>
>
> <CHOIX CODE="choix-e"/>
>
> </GRCHOIX>
>
> <GRCHOIX CODE="grchoix-D">
>
> <CHOIX CODE="choix-c"/>
>
> <CHOIX CODE="choix-d"/>
>
> </GRCHOIX>
>
> </GROUP>
>
> </FORMS>
>

I think the following XSLT 3 produces the wanted result:


<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
 B B  B xmlns:xs="http://www.w3.org/2001/XMLSchema";
 B B  B exclude-result-prefixes="#all"
 B B  B version="3.0">

 B  <xsl:output method="xml" indent="yes"/>

 B  <xsl:template match="FORMS">
 B B B  <xsl:copy>
 B B B B B  <xsl:variable name="groups" as="map(xs:untypedAtomic,
element(GRCHOIX)*)*">
 B B B B B B B  <xsl:for-each-group select="GRCHOIX" group-by="CHOIX/@CODE">
 B B B B B B B B B  <xsl:map-entry key="current-grouping-key()"
select="current-group()"/>
 B B B B B B B  </xsl:for-each-group>
 B B B B B  </xsl:variable>
 B B B B B  <xsl:iterate select="$groups">
 B B B B B B B  <xsl:param name="group" select="()"/>
 B B B B B B B  <xsl:on-completion>
 B B B B B B B B B  <GROUP>
 B B B B B B B B B B B  <xsl:sequence select="$group?*/."/>
 B B B B B B B B B  </GROUP>
 B B B B B B B  </xsl:on-completion>
 B B B B B B B  <xsl:choose>
 B B B B B B B B B  <xsl:when test="empty($group) or $group?*/CHOIX/@CODE =
?*/CHOIX/@CODE">
 B B B B B B B B B B B  <xsl:next-iteration>
 B B B B B B B B B B B B B  <xsl:with-param name="group" select="$group, ."/>
 B B B B B B B B B B B  </xsl:next-iteration>
 B B B B B B B B B  </xsl:when>
 B B B B B B B B B  <xsl:otherwise>
 B B B B B B B B B B B  <GROUP>
 B B B B B B B B B B B B B  <xsl:sequence select="$group?*/."/>
 B B B B B B B B B B B  </GROUP>
 B B B B B B B B B B B  <xsl:next-iteration>
 B B B B B B B B B B B B B  <xsl:with-param name="group" select="()"/>
 B B B B B B B B B B B  </xsl:next-iteration>
 B B B B B B B B B  </xsl:otherwise>
 B B B B B B B  </xsl:choose>
 B B B B B  </xsl:iterate>
 B B B  </xsl:copy>
 B  </xsl:template>

</xsl:stylesheet>

Current Thread