2010-09-27 8 views
21

Sto cercando di ottenere il valore di un numero a 2 dec posti dal mio xml.XSL - problema di arrotondamento/numero di formato

XML: <Quantity>0.0050</Quantity>

XSL: <xsl:value-of select="format-number($quantity, '####0.00')" />

Tuttavia XSL sembra avere un problema con questo valore e uscite 0.00 in una zona della pagina e 0.01 nell'altra. Naturalmente in questa situazione è favorevole avere l'output 0.01 in tutte le aree.

Un'altra area ha il valore 4.221 eppure l'XSL sta emettendo 4.23.

Mi rendo conto che format-number come metodo converte un numero in una stringa.

Non so come risolvere questo problema.


EDIT:

Ok, dopo un po 'di gingillarsi ho scoperto che questo funziona:

<xsl:value-of select='format-number(round(100*$quantity) div 100 ,"##0.00")' /> 

Via questa website

come questo ragazzo cita banchieri XSL usi' arrotondamento per arrotondare ai numeri pari anziché a quelli più grandi.

La soluzione non sembra elegante e significa aggiungere una tonnellata di funzioni extra a un file XSL già ingombrante e complicato. Sicuramente mi manca qualcosa?

+0

il comportamento incoerente che stai descrivendo è strano. Per favore pubblica il tuo foglio di stile. –

risposta

17

Non so perché il formato sia così incoerente, ma dalla memoria le specifiche per esso sono ... complesse.

Nel frattempo, è possibile utilizzare la funzione round (). Che è meno che perfetto, ma è funzionale. Se hai bisogno di avere un numero particolare di sig figs puoi usare THE POWER OF MATHS! e fare qualcosa di simile:

<xsl:value-of select="round(yournum*100) div 100"/>

+0

Grazie per questo! Mi ero appena imbattuto nello stesso metodo pubblicato sopra. Funziona ma significa solo instradare l'intero foglio di stile e cambiare tutto per adattarlo. Che schiffo! – Julio

+1

Non penso che questo approccio funzionerà per tutti i casi in XSLT 1.0 a causa di errori in virgola mobile (si veda la mia risposta sotto per maggiori dettagli). – Giles

14

ho avuto problemi senza fine con decimali in XSLT/XPath 1.0, spesso una combinazione di esso che rappresenta decimali come numeri in virgola mobile e con mezza anche arrotondamento (banchiere arrotondamento). Sfortunatamente, l'approccio round(yournum*100) div 100 non ha funzionato per me, a causa dell'imprecisione in virgola mobile. Ad esempio, moltiplicando 1.255 per 100 si ottiene il 125.49999999999999 (non si intende che dipenda dall'implementazione, poiché dovrebbe essere IEEE 754, ma non so se tutte le implementazioni lo rispettino). Quando arrotondato, questo dà 125, anziché 126.

Ho seguito il seguente approccio, che credo funzioni (anche se questa è sempre una zona delicata, quindi non dichiarerò troppa fiducia!). Tuttavia, dipende dal tuo motore XSLT che supporta le estensioni EXSLT. Presume che desideri arrotondare a due cifre decimali.

<func:function name="local:RoundHalfUp"> 
    <xsl:param name="number"/> 

    <xsl:choose> 
     <xsl:when test="contains($number, '.')"> 
      <xsl:variable name="decimal" select="estr:split($number, '.')[2]"/> 
      <xsl:choose> 
       <xsl:when test="string-length($decimal) &gt; 2"> 
        <func:result select="format-number(concat($number, '1'), '0.00')"/> 
       </xsl:when> 
       <xsl:otherwise> 
        <func:result select="format-number($number, '0.00')"/> 
       </xsl:otherwise> 
      </xsl:choose> 
     </xsl:when> 
     <xsl:otherwise> 
      <func:result select="format-number($number, '0.00')"/> 
     </xsl:otherwise> 
    </xsl:choose> 

</func:function> 

che può essere chiamato come:

<xsl:value-of select="local:RoundHalfUp(1.255)"/> 

Gli spazi dei nomi sono:

xmlns:func="http://exslt.org/functions" 
xmlns:estr="http://exslt.org/strings" 
xmlns:local="http://www.acme.org/local_function" 

E 'importante notare che la funzione aggiunge un '1', non aggiunge 0.001 o simile.

Sicuramente meglio usare XSLT 2.0 se è un'opzione (perché ha un decimale corretto), ma so che spesso non è un'opzione (da un'esperienza dolorosa!).