IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

XSL/XSLT/XPATH XML Discussion :

[XSL] Somme invalide


Sujet :

XSL/XSLT/XPATH XML

  1. #1
    Membre à l'essai
    Inscrit en
    Août 2004
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 20
    Points : 17
    Points
    17
    Par défaut [XSL] Somme invalide
    Bonjour à tous,

    Le passage à l'euro fait a laissé des traces, et je dois calculer deux sommes dans ma feuille XSL.
    Voici un petit exemple de la feuille XML:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
    <inscription_1 valide="true">
    	<date_inscription>2000-08-08</date_inscription>
    	<montant_creance devise="FRF">1.15E7</montant_creance>
    	<creancier id_adr_creance="AD5" id_creancier="1">
    		<coordonnee> ... </coordonnee>
    	</creancier>
    </inscription_1>
    <inscription_1 valide="true">
    	<date_inscription>2000-09-08</date_inscription>
    	<montant_creance devise="FRF">1.07002E7</montant_creance>
    	<creancier id_adr_creance="AD6" id_creancier="1">
    		<coordonnee> ... </coordonnee>
    	</creancier>
    </inscription_1>
    <inscription_1 valide="true">
    	<date_inscription>2003-10-06</date_inscription>
    	<montant_creance devise="EUR">1219592.16</montant_creance>
    	<creancier id_adr_creance="AD5" id_creancier="1">
    		<coordonnee> ... </coordonnee>
    	</creancier>
    </inscription_1>
    Il y a plus de données que ça normalement, mais le fait est que les francs et les euros sont mélangés, et que les nombre trop grands sont notés en écriture scientifique (puissance de dix).
    Lorsque j'affiche les nombres avec number() et format-number(), tout se passe bien et mon nombre apprarait tel qu'il le devrait ... mais dès que je cherche à faire une somme avec un nombre noté en puissance de dix, ça plante : NaN !

    Un petit bout de mon code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
     
    <!-- Affichage des sommes, si elles ont lieu d'être -->
    <xsl:if test="count(*[starts-with(name(),'inscription')]/montant_creance[@devise='EUR']) > 0">
    	<xsl:value-of select="format-number(number(sum(*[starts-with(name(),'inscription')]/montant_creance[@devise='EUR'])), '### ###,00','euro')" /><xsl:text> EUR</xsl:text>
    </xsl:if>
    <xsl:if test="count(*[starts-with(name(),'inscription')]/montant_creance[@devise='FRF']) > 0">
    	<xsl:if test="count(*[starts-with(name(),'inscription')]/montant_creance[@devise='EUR']) > 0">
    		<xsl:text disable-output-escaping="yes">&lt;br /&gt;</xsl:text>
    	</xsl:if>	
    	<xsl:value-of select="format-number(number(sum(*[starts-with(name(),'inscription')]/montant_creance[@devise='FRF'])), '### ###,00','euro')" /><xsl:text> FRF</xsl:text>
    </xsl:if>
     
    <!-- Affichage des montants -->
    <xsl:if test="count(*[starts-with(name(),'inscription')]) > 0">
    	<ul>
    		<xsl:for-each select="*[starts-with(name(),'inscription')]">
    			<li>
    				<p>
    					<strong>Montant créance</strong> : <xsl:value-of select="format-number(number(montant_creance), '### ###,00','euro')" /><xsl:text> </xsl:text><xsl:value-of select="montant_creance/@devise" />
    						</p>
    					</li>
    				</xsl:for-each>	
    			</ul>
    		</xsl:if>
    	</xsl:for-each>
    </xsl:if>
    J'ai bien essayé de mettre number() avant sum(), mais rien n'y fait. Par contre, si j'ai des nombres écrits "normalement", tout marche.

    Quelqu'un aurait-il une idée pour me mettre sur la piste ?

    Merci d'avance !

  2. #2
    Expert éminent
    Avatar de GrandFather
    Inscrit en
    Mai 2004
    Messages
    4 587
    Détails du profil
    Informations personnelles :
    Âge : 54

    Informations forums :
    Inscription : Mai 2004
    Messages : 4 587
    Points : 7 103
    Points
    7 103
    Par défaut
    Bonjour,

    le support de la notation scientifique pour les nombres n'est effectif que depuis la version 2.0 de XSLT. Si tu n'as pas la possibilité de changer de processeur XSLT (Saxon), il va falloir écrire des fonctions de conversion notation scientifique -> Réel et de somme.

    Par contre, je suis très étonné quand tu dis que la fonction number() a accepté de prendre un tel nombre en paramètre...

    Quel est ton processeur XSLT ?
    FAQ XML
    ------------
    « Le moyen le plus sûr de cacher aux autres les limites de son savoir est de ne jamais les dépasser »
    Giacomo Leopardi

  3. #3
    Membre à l'essai
    Inscrit en
    Août 2004
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 20
    Points : 17
    Points
    17
    Par défaut
    J'utilise le processeur XSLT intégré à Altova XMLSpy 2004 Home Edition.

    J'ai commencé à écrire une fonction, mais je sens que je vais devoir recoder la fonction "puissance" en XSL. Ca m'enchante pas des masses.

    Si je fais (number):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    <xsl:value-of select="number(*[starts-with(name(),'inscription')]/montant_creance[@devise='FRF'])" />
    Mon nombre apparait correctement, et je peux l'afficher différament avec format-number().

    Si je fais (sum) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    <xsl:value-of select="sum(*[starts-with(name(),'inscription')]/montant_creance[@devise='FRF'])" />
    Là, ça plante.

    J'en déduis donc qu'il faudrait que je transforme mon nombre avant de faire la somme, mais je n'ai pas l'impression que ça soit possible directement dans le select="". Si quelqu'un a la solution, je suis évidament preneur !

  4. #4
    Membre à l'essai
    Inscrit en
    Août 2004
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 20
    Points : 17
    Points
    17
    Par défaut
    Finalement, j'y ai été à la méthode "gros bourrin" : templates et récursivité dans tous les sens !!!

    Pour ceux que ça interesse, voici mon code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
     
    <xsl:template name="somme">
    	<xsl:param name="noeud" />
     
    	<xsl:variable name="chaine">
    		<xsl:for-each select="$noeud">
    			<xsl:value-of select="current()" />
    			<xsl:if test="not(position() = last())"><xsl:text>,</xsl:text></xsl:if>
    		</xsl:for-each>
    	</xsl:variable>
     
    	<xsl:call-template name="addition_recursive">
    		<xsl:with-param name="chaine" select="$chaine" />
    	</xsl:call-template>
     
    </xsl:template>
     
    <xsl:template name="addition_recursive">
    	<xsl:param name="chaine" />
    	<xsl:param name="base" select="0" />
     
    	<xsl:choose>
    		<xsl:when test="contains($chaine,',')">
    			<xsl:call-template name="addition_recursive">
    				<xsl:with-param name="chaine" select="substring-after($chaine,',')" />
    				<xsl:with-param name="base">
    					<xsl:call-template name="addition">
    						<xsl:with-param name="base" select="$base" />
    						<xsl:with-param name="element" select="number(substring-before($chaine,','))" />
    					</xsl:call-template>	
    				</xsl:with-param>
    			</xsl:call-template>
    		</xsl:when>
    		<xsl:otherwise>
    			<xsl:value-of select="format-number($base + number($chaine), '### ###,00','euro')" />
    		</xsl:otherwise>	
    	</xsl:choose>
    </xsl:template>
     
    <xsl:template name="addition">
    	<xsl:param name="base"	select="0" />
    	<xsl:param name="element" />
     
    	<xsl:choose>
    		<xsl:when test="contains($element,'E')">
    			<xsl:variable name="puissance">
    				<xsl:call-template name="puissance10">
    					<xsl:with-param name="x" select="substring-after($element,'E')" />
    				</xsl:call-template>
    			</xsl:variable>
    			<xsl:variable name="nombre_courrant" select="substring-before($element,'E')" />			
    			<xsl:value-of select="$base + number($nombre_courrant) * number(concat('1',$puissance))" />
    		</xsl:when>	
    		<xsl:otherwise>
    			<xsl:value-of select="$base + number($element)" />
    		</xsl:otherwise>	
    	</xsl:choose> 
    </xsl:template>
     
    <xsl:template name="puissance10">
    	<xsl:param name="x"	select="1" />
     
    	<xsl:if test="not($x=0)">
    		<xsl:text>0</xsl:text>
    		<xsl:call-template name="puissance10">
    			<xsl:with-param name="x" select="$x - 1" />
    		</xsl:call-template>
    	</xsl:if>
    </xsl:template>
    Et j'appelle tout ce bazar comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    <xsl:call-template name="somme">
    											<xsl:with-param name="noeud" select="*[starts-with(name(),'inscription')]/montant_creance[@devise='FRF']" />
    										</xsl:call-template>
    Je me doute qu'il y a forcément plus optimisé ... si quelqu'un y voit quelque chose !

  5. #5
    Expert éminent
    Avatar de GrandFather
    Inscrit en
    Mai 2004
    Messages
    4 587
    Détails du profil
    Informations personnelles :
    Âge : 54

    Informations forums :
    Inscription : Mai 2004
    Messages : 4 587
    Points : 7 103
    Points
    7 103
    Par défaut
    Plus court, moins récursif, mais pas forcément beaucoup moins bourin :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     
    	<xsl:template match="/test">
    		<resultat>
    			<xsl:call-template name="somme"> 
                	<xsl:with-param name="noeud" select="*[starts-with(name(),'inscription')]/montant_creance[@devise='FRF'][1]" /> 
                </xsl:call-template> 
    		</resultat>
    	</xsl:template>
     
    	<xsl:template name="somme">
    		<xsl:param name="noeud"/>
    		<xsl:param name="total" select="0"/>
    		<xsl:choose>
    			<xsl:when test="$noeud/node()">
    				<xsl:variable name="item">
    					<xsl:call-template name="conversion">
    						<xsl:with-param name="valeur" select="$noeud"/>
    					</xsl:call-template>
    				</xsl:variable>
    				<xsl:call-template name="somme">
    					<xsl:with-param name="noeud" select="$noeud/../following-sibling::*[starts-with(name(),'inscription')]/montant_creance[@devise='FRF'][1]"/>
    					<xsl:with-param name="total" select="$total + $item"/>
    				</xsl:call-template>			
    			</xsl:when>
    			<xsl:otherwise>
    				<xsl:value-of select="$total"/>
    			</xsl:otherwise>
    		</xsl:choose>
    	</xsl:template>
     
    	<xsl:template name="conversion">
    		<xsl:param name="valeur"/>
    		<xsl:choose>
    			<xsl:when test="contains($valeur, 'E')">
    				<xsl:variable name="prefixe" select="substring-before($valeur, 'E')"/>
    				<xsl:variable name="exposant" select="substring-after($valeur, 'E')"/>				
    				<xsl:value-of select="concat(translate($prefixe, '.', ''),substring('0000000000',1,number($exposant) - string-length(substring-after($prefixe, '.'))))"/>
    			</xsl:when>
    			<xsl:otherwise>
    				<xsl:value-of select="$valeur"/>
    			</xsl:otherwise>
    		</xsl:choose>
    	</xsl:template>
     
    </xsl:stylesheet>
    la balise test est supposée être l'élément racine de ton xml. Les exposants sont censés ne pas être supérieurs à 10, sinon faut adapter la fonction de conversion (un peu bidouille, je suis d'accord)...
    FAQ XML
    ------------
    « Le moyen le plus sûr de cacher aux autres les limites de son savoir est de ne jamais les dépasser »
    Giacomo Leopardi

  6. #6
    Membre à l'essai
    Inscrit en
    Août 2004
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 20
    Points : 17
    Points
    17
    Par défaut
    Un grand merci pour le coup de main, je vais regarder tout ça de près !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [XSL] Somme dans une variable globale ?
    Par yazman dans le forum XSL/XSLT/XPATH
    Réponses: 2
    Dernier message: 25/01/2008, 11h37
  2. [XSLT] [Xsl/Fop] Invalid byte 3 of 3-byte UTF-8 sequence
    Par Eylir dans le forum Format d'échange (XML, JSON...)
    Réponses: 2
    Dernier message: 27/12/2007, 11h49
  3. Réponses: 2
    Dernier message: 20/06/2007, 19h04
  4. [débutant][xsl]Invalid Character
    Par mavina dans le forum XSL/XSLT/XPATH
    Réponses: 8
    Dernier message: 27/07/2005, 12h24
  5. xsl : sous sommes?
    Par Slash dans le forum XSL/XSLT/XPATH
    Réponses: 2
    Dernier message: 31/03/2003, 13h34

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo