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

Subject: Re: [xsl] Grouping elements that have at least one common value
From: "Matthieu Ricaud-Dussarget ricaudm@xxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Fri, 16 Jun 2023 11:15:23 -0000
My (horrible)  XSLT solution

Message 1/2 :

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";

  xmlns:xs="http://www.w3.org/2001/XMLSchema";

  version="3.0">



  <!--==========================================================-->

  <!--MAIN-->

  <!--==========================================================-->



  <xsl:template match="/">

    <xsl:variable name="step" select="." as="document-node()"/>

    <xsl:variable name="step">

      <xsl:document>

        <xsl:apply-templates select="$step" mode="step1"/>

      </xsl:document>

    </xsl:variable>

    <xsl:variable name="step">

      <xsl:document>

        <xsl:apply-templates select="$step" mode="step2"/>

      </xsl:document>

    </xsl:variable>

    <xsl:variable name="step">

      <xsl:document>

        <xsl:apply-templates select="$step" mode="step3"/>

      </xsl:document>

    </xsl:variable>

    <xsl:variable name="step">

      <xsl:document>

        <xsl:apply-templates select="$step" mode="step4"/>

      </xsl:document>

    </xsl:variable>

    <xsl:variable name="step">

      <xsl:document>

        <xsl:apply-templates select="$step" mode="step5"/>

      </xsl:document>

    </xsl:variable>

    <xsl:sequence select="$step"/>

  </xsl:template>




<!--=========================================================================
=============-->

  <!--STEP-1-->


<!--=========================================================================
=============-->



  <!--Adding attribute choix-codes sorting values-->

  <xsl:template match="GRCHOIX" mode="step1">

    <xsl:copy>

      <xsl:apply-templates select="@*" mode="#current"/>

      <xsl:attribute name="choix-codes">

        <xsl:for-each select="CHOIX/@CODE">

          <xsl:sort/>

          <xsl:value-of select="."/>

          <xsl:if test="not(position() = last())">

            <xsl:text> </xsl:text>

          </xsl:if>

        </xsl:for-each>

      </xsl:attribute>

      <xsl:apply-templates mode="#current"/>

    </xsl:copy>

  </xsl:template>



  <!--copy template-->

  <xsl:template match="node() | @*" mode="step1">

    <xsl:copy>

      <xsl:apply-templates select="node() | @*" mode="#current"/>

    </xsl:copy>

  </xsl:template>




<!--=========================================================================
=============-->

  <!--STEP-2-->


<!--=========================================================================
=============-->



  <!--1st grouping-->

  <xsl:template match="FORMS" mode="step2">

    <xsl:copy>

      <xsl:apply-templates select="@*" mode="#current"/>

      <xsl:for-each-group select="*" group-by="tokenize(@choix-codes, ' ')">

        <group-1 key="{current-grouping-key()}">

          <xsl:variable name="choix-codes" as="xs:string*">

            <xsl:for-each
select="distinct-values(tokenize(string-join(current-group()/@choix-codes,
' '), ' '))">

              <xsl:sort/>

              <xsl:value-of select="."/>

            </xsl:for-each>

          </xsl:variable>

          <xsl:attribute name="choix-codes"
select="string-join($choix-codes, ' ')"/>

          <xsl:attribute name="count-choix-codes"
select="count($choix-codes)"/>

          <xsl:sequence select="current-group()"/>

          <!--<xsl:apply-templates select="current-group()"/>-->

        </group-1>

      </xsl:for-each-group>

    </xsl:copy>

  </xsl:template>



  <!--copy template-->

  <xsl:template match="node() | @*" mode="step2">

    <xsl:copy>

      <xsl:apply-templates select="node() | @*" mode="#current"/>

    </xsl:copy>

  </xsl:template>





Le ven. 16 juin 2023 C  13:09, Matthieu Ricaud-Dussarget ricaudm@xxxxxxxxx <
xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> a C)crit :

> Hi all,
>
>
>
> I need to group elements that have at least one common value :
>
>
>
> <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 values : choix-1, choix-2 b they
> must belong the same group
>
> * grchoix-2 and grchoix-3 have 2 common values : 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 value 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'm really not sure how to go ahead with such a grouping problem.
>
> I've tried something that work on my sample but it's probably too
> complicated (maybe it doesnt' work all cases) and most of all it has
> drastic bad performances !
>
> I'm using fro-each-group on multiple values, wich causes all combination
> to be executed and make the internal variables huge (from A 8Mo input I get
> a 500 Mo size of intermediate step)
>
> At this point I get without surprise a saxon internal error on my real
> (rather big) XML input.
>
>
>
> See my (so) bad solution in a next message (I get a message size to
> long when I copy it here)
>
>
> I'm pretty sure there's something quite more elegant to do, did you ever
> had to do such a grouping ?
>
> BTW I'm using XSLT 3.
>
>
>
> Any suggestion/help appreciated
>
>
>
>  Cheers,
>
>
> Matthieu Ricaud-Dussarget
>
>
>
>
>
>
> XSL-List info and archive <http://www.mulberrytech.com/xsl/xsl-list>
> EasyUnsubscribe <http://lists.mulberrytech.com/unsub/xsl-list/3423379> (by
> email <>)
>


--
Matthieu Ricaud-Dussarget
+33 6.63.25.95.58

Current Thread