I have the following data structure and need to output the ids of every node with every combination of v1
and v2
exactly once, where v
equals A
.
The nodes with ids 2,3,4,6,7
should be printed.
<root>
<node>
<v>A</v>
<id>2</id>
<v1>S</v1>
<v2>S</v2>
</node>
<node>
<v>A</v>
<id>3</id>
<v1>S</v1>
<v2>S1</v2>
</node>
<node>
<v>A</v>
<id>4</id>
<v1>S2</v1>
<v2>S1</v2>
</node>
<node>
<v>B</v>
<id>5</id>
<v1>S2</v1>
<v2>S3</v2>
</node>
<node>
<v>A</v>
<id>6</id>
<v1>S2</v1>
<v2>S3</v2>
</node>
<node>
<v>A</v>
<id>7</id>
<v1>S</v1>
<v2>S3</v2>
</node>
<node>
<v>A</v>
<id>8</id>
<v1>S</v1>
<v2>S</v2>
</node>
</root>
I tried using an xsl:key
, however unfortunately only unique elements are printed (id=2 is missing)
Using preceeding
as shown in the following does neither generated the desired result.
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<!-- pos 1 -->
<xsl:key name="keys" match="node" use="concat(v1, '|', v2, '|', v)"/>
<!-- /pos 1 -->
<xsl:template match="root">
<xsl:for-each select="node[v='A']">
<!-- pos 1 -->
<xsl:variable name="vDups" select="key('keys', concat(v1, '|', v2, '|', v))[not(generate-id() = generate-id(current()))]" />
<xsl:if test="not($vDups)">
<node>
<xsl:value-of select="current()/id"/>
</node>
</xsl:if>
<!-- /pos 1 -->
<!-- pos 2 -->
<xsl:if test="not(preceding::node/v1=current()/v1 and preceding::node/v2 = current()/v2)">
<node>
<xsl:value-of select="id" />
</node>
</xsl:if>
<!-- /pos 2 -->
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
How can I achieve the desired result?
You've tagged this XSLT 2.0, and have version="2.0"
in your stylesheet, in which case you can make use of xsl:for-each-group
to simplify your XSLT
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="root">
<xsl:for-each-group select="node[v = 'A']" group-by="concat(v1, '|', v2)">
<node>
<xsl:value-of select="id"/>
</node>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>