2012-10-05 13 views
10

Mam niespójność podczas korzystania XSLLiczba zaokrąglenia i precyzyjne problemy w XSLT 1.0

Oto XML,

<Rate> 
    <TotalRate>506.41</TotalRate> 
    <TotalTax>17</TotalTax> 
    <Currency>INR</Currency> 
</Rate> 

i xsl,

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"> 
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 
    <xsl:template match="/"> 
     <TotalAmount> 
      <xsl:value-of select="Rate/TotalRate + Rate/TotalTax"/> 
     </TotalAmount> 
    </xsl:template> 
</xsl:stylesheet> 

i wyjście,

<TotalAmount xmlns:fo="http://www.w3.org/1999/XSL/Format">523.4100000000001</TotalAmount> 

ale expe cted o/p jest,

<TotalAmount xmlns:fo="http://www.w3.org/1999/XSL/Format">523.41</TotalAmount> 

Dlaczego o/p jest 523.4100000000001? jak mogę uzyskać 523,41 bez zaokrąglenia go?

Odpowiedz

15

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> 
+0

dzięki, dobre, aby zobaczyć swoją odpowiedź , ale co, jeśli nie znam dokładnego miejsca po przecinku dla podanej liczby dziesiętnej? – Sujit

+0

@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ń. –

+0

@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. –