Reputation: 23
I have an XML with that estruture:
<?xml version="1.0" encoding="utf-8" ?>
<products>
<product>
<code>XXX</code>
<name>XXXXXX</name>
<variants>
<variant>
<code>XXXY</code>
<stock>5</stock>
</variant>
<variant>
<code>XXXZ</code>
<stock>8</stock>
</variant>
<variant>
<code>XXXW</code>
<stock>7</stock>
</variant>
</variants>
</product>
<product>
<code>ZZZ</code>
<name>ZZZZZZ</name>
<variants>
<variant>
<code>ZZZY</code>
<stock>5</stock>
</variant>
<variant>
<code>ZZZX</code>
<stock>8</stock>
</variant>
<variant>
<code>ZZZW</code>
<stock>7</stock>
</variant>
</variants>
</product>
</products>
I need to sort by stock and get the first "variant". The output is something like that:
<variant>
<code>XXXZ</code>
<stock>8</stock>
</variant>
<variant>
<code>ZZZX</code>
<stock>8</stock>
</variant>
Is it possible? How can I solve this?
Upvotes: 1
Views: 1521
Reputation: 1435
The code bellow should do the trick:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="products/product">
<xsl:for-each select="variants/variant">
<xsl:sort order="descending" select="stock" data-type="number"/>
<xsl:if test="position() = 1">
<xsl:apply-templates select="."/>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
<xsl:template match="variant">
<xsl:apply-templates select="code"/>
<xsl:apply-templates select="stock"/>
</xsl:template>
</xsl:stylesheet>
What we're doing here:
Upvotes: 1
Reputation: 167716
You can use xsl:perform-sort
to sort the variant
elements and then output or select the first in descending sort order:
<xsl:template match="variants">
<xsl:variable name="sorted-variants" as="element(variant)*">
<xsl:perform-sort select="variant">
<xsl:sort select="xs:integer(stock)" order="descending"/>
</xsl:perform-sort>
</xsl:variable>
<xsl:copy-of select="$sorted-variants[1]"/>
</xsl:template>
https://xsltfiddle.liberty-development.net/3NzcBsU
The same is possible using apply-templates
if the other templates (e.g. identity transformation) copy the processed variant
s:
<xsl:template match="variants">
<xsl:variable name="sorted-variants" as="element(variant)*">
<xsl:apply-templates select="variant">
<xsl:sort select="xs:integer(stock)" order="descending"/>
</xsl:apply-templates>
</xsl:variable>
<xsl:copy-of select="$sorted-variants[1]"/>
</xsl:template>
https://xsltfiddle.liberty-development.net/3NzcBsU/1
With for-each
you can directly nest an if test="position() = 1"
:
<xsl:template match="variants">
<xsl:for-each select="variant">
<xsl:sort select="xs:integer(stock)" order="descending"/>
<xsl:if test="position() = 1">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:for-each>
</xsl:template>
https://xsltfiddle.liberty-development.net/3NzcBsU/2
Upvotes: 1