Search code examples
foreachxslt-1.0xslt-groupingmuenchian-grouping

XSLT1, Muenchian grouping, listing the grouped nodes in a foreach loop


Given the xml code

<z>
<f hit="1">
<g>hola1</g>
</f>
<f hit="2">
<g>hola2</g>
</f>
<f hit="3">
<g>hola1</g>
</f>
</z>

I want to have the xml output

<z>
hola1
hola2
</z>

using xslt1. Then, an easy solution would be the muenchian grouping

<xsl:key name="thisone" match="/z/f/g" use="." />
<z>
<xsl:for-each select="/z/f[generate-id(g)=generate-id(key('thisone',g)[1])]">
<xsl:value-of select="g" />
</xsl:for-each>
</z>

However, when I apply this to a large dataset, the system (firefox) keeps thinking forever. I assume that this is due to the really large dataset. However, the number of different values of "g" is really low.

My question is: Is there any way to do a for-each loop of the nodes of the Muenchian grouping? Something like

<xsl:for-each select="nodes_of_key('thisone')">

That would avoid comparing all the values of all the "g" nodes, which takes forever?

Thanks


Solution

  • One doesn't need any <xsl:for-each> instruction to solve this problem (and this instruction is best avoided):

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>
    
     <xsl:key name="kFByG" match="f" use="g"/>
    
     <xsl:template match="/*">
         <z>
          <xsl:apply-templates/>
          <xsl:text>&#xA;</xsl:text>
         </z>
     </xsl:template>
    
     <xsl:template match="f[generate-id()=generate-id(key('kFByG',g)[1])]">
         <xsl:text>&#xA;</xsl:text>
         <xsl:value-of select="g"/>
     </xsl:template>
     <xsl:template match="text()"/>
    </xsl:stylesheet>
    

    When this transformation is applied on the provided XML document:

    <z>
        <f hit="1">
            <g>hola1</g>
        </f>
        <f hit="2">
            <g>hola2</g>
        </f>
        <f hit="3">
            <g>hola1</g>
        </f>
    </z>
    

    the wanted, correct result is produced:

    <z>
    hola1
    hola2
    </z>