Fatih Aydin
Fatih Aydin

Reputation: 5

XSLT - match decimal with string and get text

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>

Upvotes: 0

Views: 72

Answers (1)

michael.hor257k
michael.hor257k

Reputation: 117165

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

Upvotes: 2

Related Questions