¿Cómo aplicar una plantilla XSLT a un elemento tantas veces como el número de otro elemento en el documento?

Esto es un poco difícil para mí de expresar en inglés, por lo que un ejemplo podría ayudar. Digamos que tengo varios elementos llamados oración que consta de varios términos. En otra parte de XML hay un conjunto de elementos con códigos de idioma. Me gustaría aplicar una plantilla para cada oración tantas veces como idiomas y llamar a esa plantilla con el código de idioma apropiado. De esto:

<description>
    <sentences>
        <sentence>
            <term type="adjective">nice</term>
            <term type="tripType">cycling</term>
        </sentence>
        <sentence>
            <term type="adjective">boring</term>
            <term type="tripType">hike</term>
        </sentence>
    </sentences>
    <languages>
        <l>cs</l>
        <l>en</l>
    </languages>
</description>

Quiero producir algo como esto:

<div>
 <p><span>cs</span> nice cycling</p>
 <p><span>en</span> nice cycling</p>
</div>

<div>    
 <p><span>cs</span> boring hike</p>
 <p><span>en</span> boring hike</p>
</div>

Estaba tratando de usar <xsl:for-each select="/description/languages/l"> pero eso establece el contenido de l como elemento actual y ya no puedo llegar al término cosas.

Cualquier idea sería muy apreciada. Gracias

preguntado el 03 de mayo de 12 a las 09:05

3 Respuestas

<xsl:template match="description">
  <xsl:apply-templates select="sentences/sentence" />
</xsl:template>

<xsl:template match="sentence">
  <xsl:variable name="terms" select="term" />
  <div>
    <xsl:for-each select="../../languages/l">
      <p>
        <span><xsl:value-of select="." /></span>
        <xsl:apply-templates select="$terms" />
      </p>
    <xsl:for-each>
  </div>
</xsl:template>

<xsl:template match="term">
  <xsl:apply-templates select="." />
  <xsl:if test="position() &lt; last()"> </xsl:if>
</xsl:template>

contestado el 03 de mayo de 12 a las 09:05

Gracias por su ayuda, lo descubrí con la ayuda de Oliver, pero también probaré su solución, parece ser más elegante que mi código. - Lukas

Me preguntaba si la plantilla de términos en su código podría recibir de alguna manera el código de idioma de la plantilla de oración con la que se llamó. Supongo que necesitaría algún uso de <xsl:call-template>, ¿derecho? - Lukas

Respondiéndome a mí mismo :) Se puede pasar agregando <xsl:with-param name="language_code" select="." /> dentro de <xsl:apply-templates select="$terms" />. - Lukas

@Lukas Exactamente lo que iba a decir. - Tomalak

Esta transformación simple (sin condicionales explícitos):

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="sentence">
  <xsl:variable name="vSentence" select="."/>
  <div>
       <xsl:for-each select="/*/languages/l">
         <p>
           <span><xsl:value-of select="."/></span>
           <xsl:apply-templates select="$vSentence/term"/>
         </p>
       </xsl:for-each>
     </div>
 </xsl:template>

 <xsl:template match="term[position() > 1]">
  <xsl:text> </xsl:text>
  <xsl:value-of select="."/>
 </xsl:template>
 <xsl:template match="l"/>
</xsl:stylesheet>

cuando se aplica en el documento XML proporcionado:

<description>
    <sentences>
        <sentence>
            <term type="adjective">nice</term>
            <term type="tripType">cycling</term>
        </sentence>
        <sentence>
            <term type="adjective">boring</term>
            <term type="tripType">hike</term>
        </sentence>
    </sentences>
    <languages>
        <l>cs</l>
        <l>en</l>
    </languages>
</description>

produce el resultado deseado y correcto:

<div>
   <p><span>cs</span>nice cycling</p>
   <p><span>en</span>nice cycling</p>
</div>
<div>
   <p><span>cs</span>boring hike</p>
   <p><span>en</span>boring hike</p>
</div>

contestado el 03 de mayo de 12 a las 13:05

Puede asignar el elemento actual (el término material, si lo he entendido correctamente) a una variable y luego usar esa variable en el ciclo for-each: <xsl:variable name="term" select="current()"/>

contestado el 03 de mayo de 12 a las 09:05

Gracias Oliver, pero eso solo pone en la variable otra copia del contenido de l elemento (código de idioma) - Lukas

No si lo hace fuera de su bucle for-each. Creo que deberías publicar más de tu código. - Oliver

Tienes razón, me di cuenta de lo que querías decir en el momento en que publiqué el comentario. ¡Muchas gracias, Oliver, esto fue muy útil! - Lukas

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.