Home > Enterprise >  XSLT - match decimal with string and get text
XSLT - match decimal with string and get text

Time:06-18

I have problem with matching.

I wanted like below at the end.

%3,00 CCC
%5,00 AAA

%3,00 CCC
%2,00 BBB

I got a help for it and have written somethings but got an error below if more than 1 invoiceline.

Fatal Error: A sequence of more than one item is not allowed as the first argument of substring-after() ("11_003_AAA", "21_003_AAA", ...) A sequence of more than one item is not allowed as the first argument of substring-after() ("11_003_AAA", "21_003_AAA", ...)"

XML

    <invoiceLine>
        <ID>000011</ID>
        <Note>40.00 BT</Note>
        <Note>17_                       2005.00</Note>
        <Note>11_005_AAA</Note>
        <Note>11_002_BBB</Note>
        <Note>11_003_CCC</Note>
        <AllowanceCharge>
            <MultiplierFactorNumeric>0.03</MultiplierFactorNumeric>
            <Amount currencyID="USD">6.00</Amount>
        </AllowanceCharge>
        <AllowanceCharge>
            <MultiplierFactorNumeric>0.05</MultiplierFactorNumeric>
        </AllowanceCharge>
    </invoiceLine>
<invoiceLine>
        <ID>000021</ID>
        <Note>10.00 CS</Note>
        <Note>17_                       1005.00</Note>
        <Note>21_005_AAA</Note>
        <Note>21_002_BBB</Note>
        <Note>21_003_CCC</Note>
        <AllowanceCharge>
            <MultiplierFactorNumeric>0.03</MultiplierFactorNumeric>
        </AllowanceCharge>
        <AllowanceCharge>
            <MultiplierFactorNumeric>0.02</MultiplierFactorNumeric>
        </AllowanceCharge>
    </invoiceLine>

XSLT

<xsl:stylesheet version="2.0"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" version="2.0" encoding="UTF-8" indent="yes"/>

   <xsl:key name="note" match="./Note" use="substring-before(substring-after(., '_'), '_')" />

   <xsl:template match="/invoiceline">
     <xsl:for-each select="./AllowanceCharge/MultiplierFactorNumeric">
       <xsl:text> %</xsl:text>
         
       <xsl:value-of select="format-number(. * 100, '###.##0,00', 'european')"/>,
        
       <xsl:value-of select="substring-after(substring-after(key('note', format-number(100 * ., '000')), '_'), '_')"/>
            
     </xsl:for-each>
    </xsl:template>
   </xsl:stylesheet>

CodePudding user response:

First, your input is not a well-formed XML document. You must have a single root element - for example:

XML

<invoiceLines>
    <invoiceLine>
        <ID>000011</ID>
        <Note>40.00 BT</Note>
        <Note>17_                       2005.00</Note>
        <Note>11_005_AAA</Note>
        <Note>11_002_BBB</Note>
        <Note>11_003_CCC</Note>
        <AllowanceCharge>
            <MultiplierFactorNumeric>0.03</MultiplierFactorNumeric>
            <Amount currencyID="USD">6.00</Amount>
        </AllowanceCharge>
        <AllowanceCharge>
            <MultiplierFactorNumeric>0.05</MultiplierFactorNumeric>
        </AllowanceCharge>
    </invoiceLine>
    <invoiceLine>
        <ID>000021</ID>
        <Note>10.00 CS</Note>
        <Note>17_                       1005.00</Note>
        <Note>21_005_AAA</Note>
        <Note>21_002_BBB</Note>
        <Note>21_003_CCC</Note>
        <AllowanceCharge>
            <MultiplierFactorNumeric>0.03</MultiplierFactorNumeric>
        </AllowanceCharge>
        <AllowanceCharge>
            <MultiplierFactorNumeric>0.02</MultiplierFactorNumeric>
        </AllowanceCharge>
    </invoiceLine>
</invoiceLines>

Now, if you want the key to work only within the current invoiceLine, you must restrict it in some way. If you are able to use XSLT 2.0, then you can do it this way:

XSLT 2.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>

<xsl:key name="note" match="Note" use="tokenize(., '_')[2]" />
<xsl:decimal-format name="european" decimal-separator="," grouping-separator="."/>
  
<xsl:template match="/invoiceLines">
    <xsl:for-each select="invoiceLine">
        <xsl:for-each select="AllowanceCharge">
            <xsl:variable name="factor" select="100 * MultiplierFactorNumeric" />
            <xsl:text> %</xsl:text>
            <xsl:value-of select="format-number($factor, '#.##0,00', 'european')"/>
            <xsl:text> </xsl:text>
            <xsl:value-of select="tokenize(key('note', format-number($factor, '000'), ..), '_')[3]"/>
            <xsl:text>&#10;</xsl:text>
        </xsl:for-each>
        <xsl:text>&#10;</xsl:text>
    </xsl:for-each> 
</xsl:template>

</xsl:stylesheet>

to get:

Result

 %3,00 CCC
 %5,00 AAA

 %3,00 CCC
 %2,00 BBB
  • Related