Search code examples
xmlxsltmergenodesxslt-grouping

XSLT Group/merge childs (using key)


I am trying to understand how to deduce a solution using a code I already wrote.

In order to simplify I will explain first what I want to do and what I got so far.

Suppose I have an XML variable in XSLT containing few nodes with the same title attribute.

Using @Dimitre Novatchev solution I have managed to combine them into one node.

So If I had :

<t>
    <GroupData ID="xxx" Key="4" Temp="yyy">
        <ItemData ID="zzz" Value="3"/>
    </GroupData>
    <GroupData ID="yyy" Key="4" Temp="yyy">
        <ItemData ID="abc" Value="3"/>
    </GroupData>
    <GroupData ID="zzz" Temp="yyy">
        <ItemData ID="pqr" Value="1982"/>
    </GroupData>
    <GroupData ID="xxx" Key="4" Temp="yyy">
        <ItemData ID="www" Value="1982"/>
    </GroupData>
    <GroupData ID="yyy" Key="4" Temp="yyy">
        <ItemData ID="def" Value="1982"/>
    </GroupData>
    <GroupData ID="zzz" Temp="yyy">
        <ItemData ID="tuv" Value="1982"/>
    </GroupData>
</t>

After using the following key

<xsl:key name="kGDByIdKey" match="GroupData" use="concat(@ID, '+', @Key)"/>

I would get :

<t>
   <GroupData ID="xxx" Key="4" Temp="yyy">
      <ItemData ID="zzz" Value="3"/>
      <ItemData ID="www" Value="1982"/>
   </GroupData>
   <GroupData ID="yyy" Key="4" Temp="yyy">
      <ItemData ID="abc" Value="3"/>
      <ItemData ID="def" Value="1982"/>
   </GroupData>
   <GroupData ID="zzz" Temp="yyy">
      <ItemData ID="pqr" Value="1982"/>
      <ItemData ID="tuv" Value="1982"/>
   </GroupData>
</t>

Now I would like to modify this one a little bit, I would like to be able to merge/combine titles by my decision. In that in mind, in the example above I would like to define xxx and zzz to be in the same group although they are using a different title (Extreme cases - in my workspace I defined them to be identical - I might have more cases like this).

I would appreciate if you can tell me what should be the direction to do it generally ( I suppose I need to modify my key or using alternative method - generate-id or something).

I find myself implementing only bad solutions requiring a lot of unnecessary effort.


Solution

  • I would guess this is XSLT1 which is a shame as it would look nicer in XSLT2 but anyway you basically need to ensure that nodes that you want to group together end up with the same key

    <xsl:key name="kGDByIdKey" match="GroupData" use="concat(@ID, '+', @Key)"/>
    

    things only get the same use attribute if they have the same @ID and @key

    If you change that to

    <xsl:key name="kGDByIdKey" match="GroupData[not(@ID='xxx')]" use="concat(@ID, '+', @Key)"/>
    <xsl:key name="kGDByIdKey" match="GroupData[@ID='xxx'] use="concat('zzz', '+', @Key)"/>
    

    Then nodes with ID xxx will be indexed (and therefore grouped) with zzz (or course you need to make a similar change when you construct the lookup value from the node)

    If you were using xslt 2you could use a simpler functional style that is perhaps less unweildy when extended to multiple such changes

    <xsl:key name="kGDByIdKey" match="GroupData" use="concat(replace(@ID,'^xxx$','zzz'), '+', @Key)"/>