Using xslt/xpath, I need to be able to select the two elements which have the lowest attribute value and merge them, in a way. Lets say for example I have:
<root>
<integer val="14"/>
<integer val="7"/>
<integer val="2"/>
<integer val="1"/>
<integer val="4"/>
<integer val="8"/>
</root>
I want to select the two lowest values (1 and 2) and represent them as one element in the output. The attribute value should be the sum of these two lowest values, so I want:
<root>
<integer val="3"/>
</root>
I am also constrained to using only xslt 1.0, as the xml is to be processed with the java 1.5 api, which does not seem to support xslt 2.0. What should i do to make my stylesheet solve this seemingly simple task?
My first attempt was to use sorting:
<xsl:template match="root">
<xsl:copy>
<xsl:apply-templates select="integer">
<xsl:sort data-type="number" select="@val"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="integer[1]">
<xsl:copy>
<xsl:attribute name="val">
<xsl:value-of select="@val + ../integer[2]/@val"/>
</xsl:attribute>
</xsl:copy>
</xsl:template>
This however results in nothing. Only an empty root node. Apparently, the <xsl:sort> disables the ability to do <xsl:template match="integer[1]"> (the [1] part is the part that does not work together with the sort). And, even if it did work, the [1] seems to refer to the document order, not the sorted order. Changing the second template to:
<xsl:template match="integer">
<xsl:copy>
<xsl:attribute name="val">
<xsl:value-of select="../integer[2]/@val"/>
</xsl:attribute>
</xsl:copy>
</xsl:template>
Results in output where all output val attributes are 7 (instead of 2, which I wanted it to be)
Another approach was to use the min() xpath function. This however, failed fast since min() is not available in 1.0. And, even if min were available, it would not be trivial to find the two smallest elements and merge those.