Search code examples
xslt

Preserver order in maps (XSLT)


I need to process and group items from the following string:

"fl, ob1, ob2, cordib (Fa), fag1, fag2, cor1 (Fa), cor2 (Fa), vl1, vl2, vla1, vla2, Vitellia, vlc-b"

I tried to implement it utilizing maps and recursive templates approach and result should like this:

map {
"fl":  1,
"ob": 2,
"cordib": 1,
"fag": 2, 
...
"vlc-b": 1
}

I need to preserve the order, but by default maps does not seem to allow this. Is it possible to enable this?

Colud there be any other aproach to achieve this in XSLT?


Solution

  • You could use for-each-group on the tokenized string, that preserves the order, as the data type, if you want to use maps, I see an option of a sequence of maps e.g.

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      version="3.0"
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      exclude-result-prefixes="#all"
      expand-text="yes">
      
      <xsl:param name="input" as="xs:string" expand-text="no">"fl, ob1, ob2, cordib (Fa), fag1, fag2, cor1 (Fa), cor2 (Fa), vl1, vl2, vla1, vla2, Vitellia, vlc-b"</xsl:param>
    
      <xsl:output method="adaptive"/>
    
      <xsl:template match="/" name="xsl:initial-template">
        <xsl:variable name="groups" as="map(xs:string, xs:integer)*">
          <xsl:for-each-group select="tokenize($input, '\s*,\s*') ! replace(., '^&quot;|&quot;$', '') ! replace(., '[ 0-9]+', '') ! replace(., '\(.*\)', '')" group-by=".">
            <xsl:sequence select="map { current-grouping-key() : count(current-group()) }"/>
          </xsl:for-each-group>
        </xsl:variable>
        <xsl:sequence select="$groups"/>
      </xsl:template>
      
    </xsl:stylesheet>
    

    Online fiddle.