W XSLT 1.0 numery są realizowane z podwójnym typu i jak z każdym binarnym zmiennoprzecinkowych typu, dochodzi do utraty precyzji.
W XSLT 2.0/XPath 2.0 można używać typu xs:decimal
do pracy bez utraty precyzji.
I. XSLT 1.0 rozwiązanie:
Użyj format-number()
funkcję:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/*">
<TotalAmount>
<xsl:value-of select="format-number(TotalRate + TotalTax, '0.##')"/>
</TotalAmount>
</xsl:template>
</xsl:stylesheet>
Kiedy transformacja ta jest stosowana na dostarczonych dokumentów XML:
<Rate>
<TotalRate>506.41</TotalRate>
<TotalTax>17</TotalTax>
<Currency>INR</Currency>
</Rate>
The Wanted, poprawny wynik jest produkowany:
<TotalAmount>523.41</TotalAmount>
Tutaj jest również przykładem, pokazując, że poszukiwany precyzja maynot być statycznie znane i mogą być przekazywane do transformacji jako zewnętrzny/parametr globalny:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="pPrec" select="2"/>
<xsl:param name="pPrec2" select="13"/>
<xsl:variable name="vPict" select="'##################'"/>
<xsl:template match="/*">
<TotalAmount>
<xsl:value-of select=
"format-number(TotalRate + TotalTax,
concat('0.', substring($vPict,1,$pPrec))
)"/>
</TotalAmount>
<TotalAmount>
<xsl:value-of select=
"format-number(TotalRate + TotalTax,
concat('0.', substring($vPict,1,$pPrec2))
)"/>
</TotalAmount>
</xsl:template>
</xsl:stylesheet>
Kiedy transformacja ta jest stosowana na dostarczonym dokumencie XML, dwa wyniki są produkowane - z precyzją i dokładnością 2 13:
<TotalAmount>523.41</TotalAmount>
<TotalAmount>523.4100000000001</TotalAmount>
II. XSLT 2.0 rozwiązanie wykorzystujące xs:decimal
:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<TotalAmount>
<xsl:value-of select="xs:decimal(TotalRate) + xs:decimal(TotalTax)"/>
</TotalAmount>
</xsl:template>
</xsl:stylesheet>
Gdy ta transformacja jest stosowane na tym samym dokumencie XML (powyżej), chciał, poprawny wynik jest produkowany:
<TotalAmount>523.41</TotalAmount>
dzięki, dobre, aby zobaczyć swoją odpowiedź , ale co, jeśli nie znam dokładnego miejsca po przecinku dla podanej liczby dziesiętnej? – Sujit
@asdasd, Jeśli go nie znasz, możesz przekazać go do transformacji jako parametr globalny - wtedy jakiś dodatkowy kod XSLT może dynamicznie konstruować pożądany argument 'format-number()'. Zobacz także moje rozwiązanie XSLT 2.0, w którym możesz użyć typu 'xs: decimal' do dokładnych obliczeń. –
@asdasd, Proszę zobaczyć moją zaktualizowaną odpowiedź. Dodałem rozwiązanie, gdy pożądana precyzja nie jest znana z góry i jest przekazywana do transformacji jako parametr. –