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> </xsl:text>
</xsl:for-each>
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
to get:
Result
%3,00 CCC
%5,00 AAA
%3,00 CCC
%2,00 BBB
