I'm trying to sort xml with xslt but the problem is that my code only sort elements under specific node, here is a sample xml:
<region name="Germany">
<company name="Mercedes" rank="2" />
<company name="BMW" rank="3" />
</region>
<region name="Japan">
<company name="Toyota" rank="1" />
<company name="Mazda" rank="4" />
</region>
I tried the folowing but it didn't work
<xsl:template match="region">
<Companies>
<xsl:for-each select="company">
<xsl:sort select="@rank" />
<xsl:call-template name="companies">
</xsl:for-each>
</Companies>
</xsl:template>
<xsl:template name="companies">
<Company>
<xsl:value-of select="@name" />
</Company>
</xsl:template>
the output should be:
<Companies>
<Company>Toyota</Company>
<Company>Mercedes</Company>
<Company>BMW</Company>
<Company>Mazda</Company>
</Companies>
You haven't shown any container element for those region
elements but assuming you have them inside one common container write a template matching that container (e.g. named root
in the sample code below) and then I would simply suggest to apply-templates to the company
grandchildren with an xsl:sort
included based on the rank
attribute.
Then add a template transforming from the attribute based company
input elements to a value based element and you are done:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="root">
<Companies>
<xsl:apply-templates select="region/company">
<xsl:sort select="xs:integer(@rank)"/>
</xsl:apply-templates>
</Companies>
</xsl:template>
<xsl:template match="company">
<xsl:copy>
<xsl:value-of select="@name"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/94rmq6B
Matching on each region
doesn't seem to make sense if you want to process them all together in a sorted way.