2009-08-21 7 views
1

J'ai un XML comme ceci:augmentation automatique conditionnelle dans xsl

<V> 
    <W> 
    <X>1</X> 
    </W> 
    <W> 
    <Y>1</Y> 
    </W> 
    <W> 
    <X>1555</X> 
    </W> 
    <W> 
    <X>1</X> 
    </W> 
</V> 

Je veux faire quelque chose comme ceci:

<entity ID="start"> 
    <f ID="NewField">0001</f> 
    <f ID="NewField">0001</f> 
    <f ID="NewField">0002</f> 
    <f ID="NewField">0003</f> 
</entity> 

Lorsque le champ est V/W/X alors NewField devrait être incrémenté de 1 autant de fois que l'étiquette V/W/X est trouvée. De même pour V/W/Y.

Le XSL que je me sers est

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:template match="/"> 
<entity ID="start"> 
    <xsl:for-each select="V/W"> 
     <xsl:if test="X"> 
      <xsl:variable name="my_var"> 
       <xsl:value-of select="concat('000',position())"/> 
      </xsl:variable> 
      <f ID="NewField"><xsl:value-of select="$my_var"/></f> 
     </xsl:if> 
     <xsl:if test="Y"> 
      <xsl:variable name="my_var"> 
       <xsl:value-of select="concat('000',position())"/> 
      </xsl:variable> 
      <f ID="NewField"><xsl:value-of select="$my_var"/></f> 
     </xsl:if> 
    </xsl:for-each> 
</entity> 
</xsl:template> 
</xsl:stylesheet> 

mais il me donne un mauvais résultat, quelque chose comme ceci:

<entity ID="start"> 
    <f ID="NewField">0001</f> 
    <f ID="NewField">0002</f> 
    <f ID="NewField">0003</f> 
    <f ID="NewField">0004</f> 
</entity> 

Répondre

0

Je pense que vous cherchez quelque chose comme count(preceding::X) expression. Bien sûr, vous voudrez peut-être le rendre plus complexe et ensuite prendre soin de la mise en forme des nombres, mais cela semble être le point de départ que vous recherchez.

0
<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
> 
    <xsl:template match="V"> 
    <entity ID="start"> 
     <xsl:apply-templates select="W/X|W/Y" /> 
    </entity> 
    </xsl:template> 

    <xsl:template match="X|Y"> 
    <f ID="NewField"> 
     <xsl:variable name="counter" select=" 
     count(
      parent::W/preceding-sibling::W/*[name() = name(current())] 
     ) + 1 
     " /> 
     <xsl:value-of select="format-number($counter, '0000')" /> 
    </f> 
    </xsl:template> 

</xsl:stylesheet> 

Ce:

parent::W/preceding-sibling::W/*[name() = name(current())]

sélectionne tous les éléments précédents de la même nom que l'élément courant. Par exemple, si le point d'exécution est sur ce noeud:

<X>1555</X> 

Il va d'un niveau (parent::W), sélectionne ensuite tous les <W> frères et sœurs précédentes, et de ceux qu'il sélectionne un enfant (*) qui a un nom de X - puisque X est le nom de l'élément current().

L'ensemble de nœuds résultant est compté et incrémenté de un. format-number() est utilisé pour générer une belle sortie propre:

<entity ID="start"> 
    <f ID="NewField">0001</f> 
    <f ID="NewField">0001</f> 
    <f ID="NewField">0002</f> 
    <f ID="NewField">0003</f> 
</entity> 
+0

Par curiosité, est-il une raison particulière pour laquelle vous utilisez le ' parent :: 'axe explicitement (qui par définition n'a jamais plus qu'un nœud) plutôt que' ..' - il semble que ce soit un peu ambigu. –

+0

Vous avez raison, ''..' 'est le même, et je le sais. Je le fais parce que pour moi c'est plus expressif. Lors de la lecture du XPath, la structure du document anticipé est claire instantanément, tandis que ''..' 'laisse un reste d'ambiguïté. – Tomalak

1

Si vous voulez noeuds nombre avec XSLT puis the xsl:number element peut aider:

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0"> 

    <xsl:output indent="yes"/> 

    <xsl:template match="/"> 
    <entity ID="start"> 
     <xsl:apply-templates select="descendant::X | descendant::Y"/> 
    </entity> 
    </xsl:template> 

    <xsl:template match="X | Y"> 
    <f ID="NewField"><xsl:number level="any" format="0000"/></f> 
    </xsl:template> 

</xsl:stylesheet>