Posez votre question Signaler

XSLT - boucle et variable

stephbibie - Dernière réponse le 3 mars 2008 à 15:06
Bonjour,
Je dois transformer un fichier XML en un autre fichier XML à l'aide de XSLT.
Dans mon fichier XML d'origine, j'ai un élément qui peut-être répété plusieur fois à la suite.
Ce que je veux faire c'est garder uniquement la première occurence non nulle. Et si elles sont toutes nulles, gardé une seule occurence (nulle).
exemple 2 :
<package>
      <package_desc></package_desc>
      <package_desc>Pkg Desc1</package_desc>
      <package_desc>Pkg Desc2</package_desc>
</package> 

donne :
<package>
      <package_desc>Pkg Desc1</package_desc>
</package> 

exemple 1 :
<package>
      <package_desc></package_desc>
      <package_desc></package_desc>
</package> 

donne :
<package>
      <package_desc></package_desc>
</package> 

Je pensais faire ça avec une boucle for-each en utilisant une variable, genre "elementTrouvé" pour savoir si une occurrence a déjà été trouvée.
Mais apparemment, j'ai vu que ce n'est pas possible de modifier une variable en XSLT.
Je ne vois donc pas vraiment comment faire.
Quelqu'un aurait-il une solution ?
Lire la suite 

XSLT - boucle et variable »

6 réponses
Réponse
+0
moins plus
le xsl peut être celui-là :

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>

<xsl:template match="package">
<xsl:copy>
<xsl:call-template name="get_premier_non_vide">
<xsl:with-param name="index" select="1"/>
</xsl:call-template>
</xsl:copy>
</xsl:template>

<xsl:template name="get_premier_non_vide">
<xsl:param name="index"/>

<xsl:if test="package_desc[$index]">

<xsl:choose>
<xsl:when test="package_desc[$index]/text() != ''">
<xsl:copy-of select="package_desc[$index]"/>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="get_premier_non_vide">
<xsl:with-param name="index" select="$index + 1"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:if>

</xsl:template>

</xsl:stylesheet>
stephbibie - 3 mars 2008 à 11:37
Merci beaucoup tomlecabron,

effectivement ça correspond davantage à mes besoins.
Par contre j'ai voulu rajouter la condition qui dit que si aucun élément non null n'a été trouvé, il faut copier le dernier élément null, mais une fois de plus je n'y arrive pas (je crois que XSLT n'ait pas fait pour moi). J'ai fait ça :
<xsl:template match="package_desc">
        <xsl:if test="not(preceding-sibling::*[text() != '' and name() = name(current())]) and (text() != ''" or  current()[position()=last()])>
                 <xsl:copy-of select="."/>
        </xsl:if>
</xsl:template> 


et pour l'exemple suivant :
<package id="idPack1">
	.........
	<package_desc language="default"></package_desc>
	<package_desc language="default">Pkg Desc2</package_desc>
	<package_desc language="default"></package_desc>
        ......
</package>    
<package id="idPack2">
	.........
	<package_desc language="default"></package_desc>
	<package_desc language="default"></package_desc>
        ......
</package>  


cela donne :
<package id="idPack1">
	.........
	<package_desc language="default"></package_desc>
	<package_desc language="default">Pkg Desc2</package_desc>
        ......
</package>    
<package id="idPack2">
	.........
	<package_desc language="default"></package_desc>
	<package_desc language="default"></package_desc>
        ......
</package>         



autre chose, je n'arrive toujours pas à intégrer ma suppression d'attribut:
par exemple dans l'exemple précédent,je veux supprimer l'attribut language.
En ajoutant la ligne
<xsl:template match="package_desc/@language" />
à la feuille de style, cela ne fonctionne pas. j'imagine que c'est parce que la précédente règle
 <xsl:template match="package_desc">
surchage cette règle. Mais du coup je ne vois pas comment faire.
stephbibie - 3 mars 2008 à 14:29
C'est bon pour la suppression des attributs, j'ai réussi à m'en sortir, j'ai fait comme ça et ça semble fonctionner:
<xsl:template match="package_desc">
	<xsl:if test="not(preceding-sibling::*[text() != '' and name() = name(current())]) and text() != ''">
		<xsl:copy >
		<xsl:apply-templates select="attribute::*[name()!='language']|node()"/>
		</xsl:copy>
	</xsl:if>
</xsl:template>


Il ne manque plus qu'à trouver une solution pour mon histoire de dernier élément null et j'en aurais fini avec XSLT...pour cette fois!
stephbibie - 3 mars 2008 à 15:06
Bon ça y est,
j'ai finalement trouvé une solution pour mon problème de dernier null. Je sais pas si c'est la meilleure façon de le faire mais en tout cas ça à l'air de fonctionner :
<xsl:if test="not(preceding-sibling::*[text() != '' and name() = name(current())]) 
	              and (text() != '' or not(following-sibling::*[name() = name(current())]))">
		<xsl:copy >
			<xsl:apply-templates select="attribute::*[name()!='language']|node()"/>
		</xsl:copy>
	</xsl:if>



En tout cas, merci encore, je ne pense pas que je m'en serais sorti sans ton aide précieuse!
Ajouter un commentaire
Ce document intitulé « XSLT - boucle et variable » issu de CommentCaMarche (www.commentcamarche.net) est mis à disposition sous les termes de la licence Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.
Dossier à la une
Passage au tout numérique : quel coût pour les particuliers ?