XSLT 2.0 - Sorting issue

2019-07-10 00:49发布

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

1条回答
ら.Afraid
2楼-- · 2019-07-10 01:02

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)),'&#x9;')"/>
    <xsl:text>&#xA;</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)
      ),'&#xA;')"/>
  </xsl:template>

</xsl:stylesheet>

Updated fiddle: http://xsltfiddle.liberty-development.net/948Fn5o/3

查看更多
登录 后发表回答