Search code examples
sortingxsltgroupingunique

XSL - store unique and sorted data in a variable


Using XSLT 2.0 and Apache FOP I want to be able to create a new variable, have unique and sorted values inside it by category but preserve the nodes. So the new variable should have the following nodes:

<category>1. First Aid</category>
<category>2. Access control</category>
<category>3. Fire safety</category>
<category>4. Recognition</category>

The input XML is the following:

<equipment>
    <E0132>
        <category>1. First Aid</category>
        <description>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</description>
    </E0132>
    <E0133>
        <category>1. First Aid</category>
        <description>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</description>
    </E0133>
    <E4122>
        <category>3. Fire safety</category>
        <description>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</description>
    </E4122>
    <E4182>
        <category>3. Fire safety</category>
        <description>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</description>
    </E4182>
    <E4622>
        <category>2. Access control</category>
        <description>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</description>
    </E4622>
    <E5225>
        <category>4. Recognition</category>
        <description>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</description>
    </E5225>
</equipment>

In regard to the XSL, this is what I have so far:

<xsl:variable name="equipment">
    <xsl:for-each-group select="//equipment/node()" group-by="category">
        <xsl:sort select="." order="ascending" />
        <xsl:value-of select="."/>              
    </xsl:for-each-group>        
</xsl:variable>

But it's not working as expected. It doesn't contain the category nodes as I would like to and I don't know how to integrate distinct-values() XSL function here in order to achieve unicity.


Solution

  • You can use the current-grouping-key() function to store the values. Below is the updated variable declaration.

    <xsl:variable name="equipment">
        <xsl:for-each-group select="//equipment/*/category" group-by=".">
            <xsl:sort select="." order="ascending" />
            <category>
                <xsl:value-of select="current-grouping-key()"/>
            </category>              
        </xsl:for-each-group>   
    </xsl:variable>
    

    To check the variable contents

    <xsl:copy-of select="$equipment" />
    

    gives output as

    <category>1. First Aid</category>
    <category>2. Access control</category>
    <category>3. Fire safety</category>
    <category>4. Recognition</category>
    

    EDIT: To print the variable values within a loop, try the below

    <!-- print variable values -->
    <xsl:for-each select="$equipment/category" >
        <xsl:value-of select="." />
        <xsl:text>&#xA;</xsl:text>
    </xsl:for-each>
    

    Output

    1. First Aid
    2. Access control
    3. Fire safety
    4. Recognition