consider this code
<xsl:variable name="sequence" select="
( map { 'foo' : 1, 'bar' : () },
map { 'foo' : 1, 'bar' : () },
map { 'foo' : 1, 'bar' : '3' } )" as="map(xs:string,item()*)*"/>
<xsl:variable name="distinct" as="map(xs:string,item()*)*">
<xsl:for-each-group select="$sequence" group-by="map:get(.,'bar')">
<xsl:sequence select="map { 'group' : current-grouping-key() }"/>
</xsl:for-each-group>
</xsl:variable>
I want the result to be
( map { 'group' : () }
map { 'group' : 3 } )
but it gives me
( map { 'group' : 3 } )
(which I actually find a little odd)
how can you elegantly handle the above in XSLT?
(I've tried wrapping the group expression in an array, but it secretly maps that to a sequence and then discards it as empty, and maps don't work in group-by expressions)
I think this works
<xsl:variable name="sequence" select="
( map { 'foo' : 1, 'bar' : () },
map { 'foo' : 1, 'bar' : () },
map { 'foo' : 1, 'bar' : '3' } )" as="map(xs:string,item()*)*"/>
<xsl:variable name="distinct" as="map(xs:string,item()*)*">
<xsl:for-each-group select="$sequence" group-by="map:get(.,'bar')" composite="true">
<xsl:sequence select="map { 'group' : current-grouping-key() }"/>
</xsl:for-each-group>
</xsl:variable>
i.e. if composite is set to true, then ()
is not thrown away as a key.
https://www.w3.org/TR/2017/REC-xslt-30-20170608/#xsl-for-each-group
If
composite="yes"
is specified, there will be a single grouping key, which will in general be a sequence of zero or more atomic values; otherwise, there will be zero or more grouping keys, each of which will be a single atomic value.