Contador dentro de xsl: para cada bucle

89

Cómo obtener un contador dentro de xsl: for-each loop que reflejaría el número de elemento actual procesado.
Por ejemplo, mi XML de origen es

<books>
    <book>
        <title>The Unbearable Lightness of Being </title>
    </book>
    <book>
        <title>Narcissus and Goldmund</title>
    </book>
    <book>
        <title>Choke</title>
    </book>
</books>

Lo que quiero conseguir es:

<newBooks>
    <newBook>
        <countNo>1</countNo>
        <title>The Unbearable Lightness of Being </title>
    </newBook>
    <newBook>
        <countNo>2</countNo>
        <title>Narcissus and Goldmund</title>
    </newBook>
    <newBook>
        <countNo>3</countNo>
        <title>Choke</title>
    </newBook>
</newBooks>

El XSLT para modificar:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:template match="/">
        <newBooks>
            <xsl:for-each select="books/book">
                <newBook>
                    <countNo>???</countNo>
                    <title>
                        <xsl:value-of select="title"/>
                    </title>
                </newBook>
            </xsl:for-each>
        </newBooks>
    </xsl:template>
</xsl:stylesheet>

Entonces la pregunta es qué poner en lugar de ???. ¿Existe alguna palabra clave estándar o simplemente debo declarar una variable e incrementarla dentro del ciclo?

Como la pregunta es bastante larga, probablemente debería esperar una respuesta de una línea o una palabra :)

kristof
fuente

Respuestas:

141

position(). P.EJ:

<countNo><xsl:value-of select="position()" /></countNo>
cuadrado rojo
fuente
9
Todo esto está bien hasta que tenga que agregar un filtro como xsl: if dentro de su xsl: for-each. Entonces la posición () es INÚTIL y necesita un contador adecuado.
Mike Starov
4
@Mike Stavrov ¡Eso no era parte de la pregunta! No se pueden cubrir todas las situaciones
redsquare
@redsquare Correcto. Solo agrego mis dos centavos. Tuve que escribir una función de extensión XSL para resolver mi situación descrita. Quizás debería preguntarle a la gente aquí sobre mejores soluciones.
Mike Starov
2
@MikeStarov, entonces, ¿cómo se hace si hay un xsl:ifdentro del xsl:for-each? ¿Qué es un "contador adecuado"? ¿Puedes señalar algún recurso?
lajarre
@lajarre Escribe una función de extensión personalizada para ser llamada desde XSL. También puede realizar el procesamiento de dos pases. Procese una vez y guarde en xsl: variable. Luego aplique plantillas en el contenido de la variable xsl y agregue numeración usando position ()
Mike Starov
13

Intente insertar <xsl:number format="1. "/><xsl:value-of select="."/><xsl:text>en el lugar de ???.

Tenga en cuenta el "1": este es el formato de número. Más info: aquí

m_pGladiator
fuente
Gracias, esa es una lectura interesante también. Probablemente usaré ese enfoque cuando se requiera algo de formato
kristof
Versión XSLT 1.0:<xsl:number format="1. " value="position()"/>
jsuddsjr
10

Tratar:

<xsl:value-of select="count(preceding-sibling::*) + 1" />

Editar : tenía el cerebro congelado allí, ¡la posición () es más sencilla!

Luke Bennett
fuente
3
Aún podría ser útil, especialmente si está seleccionando basándose en criterios distintos a la posición (). +1
jsuddsjr
7

También puede ejecutar declaraciones condicionales en Postion () que pueden ser realmente útiles en muchos escenarios.

por ej.

 <xsl:if test="(position( )) = 1">
     //Show header only once
    </xsl:if>
Arun Arangil
fuente
2
Esto falla si tiene un filtro como xsl: sort porque es posible que el primer elemento no sea el primero en procesarse.
Alexis Wilke
5
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:template match="/">
        <newBooks>
                <xsl:for-each select="books/book">
                        <newBook>
                                <countNo><xsl:value-of select="position()"/></countNo>
                                <title>
                                        <xsl:value-of select="title"/>
                                </title>
                        </newBook>
                </xsl:for-each>
        </newBooks>
    </xsl:template>
</xsl:stylesheet>
Santiago Cepas
fuente