I am offering a total of three alternative solutions each short and simple (no nested <xsl:for-each>
and no sorting). If it is possible, I'd recommend using the XSLT 2.0 solution.
I. Two alternative XSLT 1.0 solutions:
1. Without keys:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="available">
<xsl:if test=
"not(@price
>
( preceding-sibling::available
|
following-sibling::available
)
[substring(@date, 1, 7)
=
substring(current()/@date, 1, 7)
]
/@price
)">
<xsl:call-template name="identity"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
2. Using keys:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kDateByMonth" match="available"
use="substring(@date, 1, 7)"/>
<xsl:template match=
"available
[generate-id()
=
generate-id(key('kDateByMonth',
substring(@date, 1, 7)
)[1]
)
]
">
<xsl:variable name="vsameMonth" select=
"key('kDateByMonth',
substring(@date, 1, 7)
)
"/>
<xsl:copy-of select=
"$vsameMonth[not(@price > $vsameMonth/@price)][1]
"/>
</xsl:template>
</xsl:stylesheet>
when any of the two transformations above is applied to the provided XML document:
the wanted, correct result is produced:
<tour id="12314">
<available date="2012-04-19" price="533"/>
<available date="2012-05-25" price="600"/>
<available date="2012-06-20" price="705"/>
</tour>
Note: In the question it wasn't specified what to output if more than one tour in a month have the same minimum price. The first transformation will output all such tours (and probably will give choice to the reader), while the second transformation outputs only one such tour per month. Both transformations can be modified to implement the other behavior.
II. An XSLT 2.0 solution:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/*">
<xsl:for-each-group select="*"
group-by="substring(@date, 1,7)">
<xsl:copy-of select=
"current-group()
[@price
=
min(current-group()/@price/number())
]
[1]"/>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>