Contador dentro de xsl: for-each loop

89

Como obter um contador dentro de xsl: for-each loop que refletiria o número do elemento atual processado.
Por exemplo, meu XML de origem é

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

O que eu quero é:

<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>

O 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>

Portanto, a questão é o que colocar no lugar de ???. Existe alguma palavra-chave padrão ou devo simplesmente declarar uma variável e incrementá-la dentro do loop?

Como a pergunta é muito longa, provavelmente devo esperar uma resposta de uma linha ou uma palavra :)

Kristof
fonte

Respostas:

141

position(). POR EXEMPLO:

<countNo><xsl:value-of select="position()" /></countNo>
quadrado vermelho
fonte
9
Isso está tudo bem e elegante até que você tenha que adicionar um filtro como xsl: if dentro de seu xsl: for-each. Então a posição () é INÚTIL e você precisa do contador adequado.
Mike Starov
4
@Mike Stavrov Isso não fazia parte da questão! Não é possível cobrir todas as situações
redsquare
@redsquare correto. Apenas adicionando meus dois centavos. Tive que escrever uma função de extensão XSL para resolver minha situação descrita. Talvez eu devesse perguntar às pessoas aqui sobre soluções melhores.
Mike Starov
2
@MikeStarov então como fazer se houver um xsl:ifdentro do xsl:for-each? O que é um "contador adequado"? Você pode apontar para algum recurso?
lajarre
@lajarre Você escreve uma função de extensão customizada para ser chamada a partir do XSL. Você também pode fazer o processamento de duas passagens. Processe uma vez e salve em xsl: variable. Em seguida, aplique modelos em conteúdos de variáveis ​​xsl e adicione numeração usando position ()
Mike Starov
13

Tente inserir <xsl:number format="1. "/><xsl:value-of select="."/><xsl:text> no lugar de ???.

Observe o "1" - este é o formato de número. Mais informações: aqui

m_pGladiator
fonte
Obrigado, essa também é uma leitura interessante. Provavelmente usarei essa abordagem quando alguma formatação for necessária
Kristof
Versão XSLT 1.0:<xsl:number format="1. " value="position()"/>
jsuddsjr
10

Experimentar:

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

Editar - teve um congelamento do cérebro, position () é mais simples!

Luke Bennett
fonte
3
Ainda pode ser útil, especialmente se você estiver selecionando com base em critérios diferentes de position (). +1
jsuddsjr
7

Você também pode executar instruções condicionais no Postion (), o que pode ser realmente útil em muitos cenários.

por exemplo.

 <xsl:if test="(position( )) = 1">
     //Show header only once
    </xsl:if>
Arun Arangil
fonte
2
Isso falhará se você tiver um filtro como xsl: sort porque o primeiro item pode não ser o primeiro a ser processado.
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
fonte