I have below input XML and I am facing issue while sorting number using XSLT. I have tried multiple logic but not able to generate expected result. I am able to sort the data when it is having only one AccountNo but facing issue when record is having multiple AccountNo and throwing error that too many sort key values. I want to sort the data by AccountNo.
<-------XML Data---------->
<?XML version="1.0" encoding="UTF-8">
<Bank>
<Customer>
<Account>
<AccountNo>999</AccountNo>
<AccountNo>1004</AccountNo>
<AccountNo>1002</AccountNo>
</Account>
<FirstName>Ramesh</FirstName>
<LastName>Patel</LastName>
<ContactNo>1234567890</ContactNo>
</Customer>
<Customer>
<Account>
<AccountNo>1001</AccountNo>
</Account>
<FirstName>Viraj</FirstName>
<LastName>Shah</LastName>
<ContactNo>4567890989</ContactNo>
</Customer>
<Customer>
<Account>
<AccountNo>1003</AccountNo>
<AccountNo>1005</AccountNo>
</Account>
<FirstName>Kapil</FirstName>
<LastName>Sharma</LastName>
<ContactNo>3456789320</ContactNo>
</Customer>
</Bank>
<---------Expected output------->
999 Ramesh Patel 1234567890
1001 Viraj Shah 4567890989
1002 Ramesh Patel 1234567890
1003 Kapil Sharma 3456789320
1004 Ramesh Patel 1234567890
1005 Kapil Sharma 3456789320
What I would do is apply-templates to all AccountNo
elements and sort them.
Then match AccountNo
and output the entry...
XSLT 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<xsl:apply-templates select=".//AccountNo">
<xsl:sort data-type="number"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="AccountNo">
<xsl:value-of select="string-join((.,../../(FirstName,LastName,ContactNo)),'	')"/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
Output
1000 Ramesh Patel 1234567890
1001 Viraj Shah 4567890989
1002 Ramesh Patel 1234567890
1003 Kapil Sharma 3456789320
1004 Ramesh Patel 1234567890
1005 Kapil Sharma 3456789320
Working fiddle: http://xsltfiddle.liberty-development.net/948Fn5o
UPDATE
Since your output is supposed to be in a fixed field, I'd suggest creating a function that you can use to pad a string with spaces to fit the field. This will allow you to guarantee that the field is exactly the width you want.
Example...
XSLT 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:l="local">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<xsl:apply-templates select=".//AccountNo">
<xsl:sort data-type="number"/>
</xsl:apply-templates>
</xsl:template>
<!--Note: If the string to pad is longer than the width specified, the string
will be truncated to fit the width.-->
<xsl:function name="l:pad">
<xsl:param name="toPad" as="xs:string?"/>
<xsl:param name="width" as="xs:integer"/>
<xsl:variable name="padding"
select="for $x in 1 to $width - string-length(normalize-space($toPad)) return ' '"/>
<xsl:value-of
select="substring(
concat(normalize-space($toPad), string-join($padding,'')),
1,$width)"/>
</xsl:function>
<xsl:template match="AccountNo">
<xsl:value-of select="(
l:pad(.,8),
../../(
l:pad(FirstName,8),
l:pad(LastName,8),
l:pad(ContactNo,10)
),'
')"/>
</xsl:template>
</xsl:stylesheet>
Updated fiddle: http://xsltfiddle.liberty-development.net/948Fn5o/3