Pergunta

Eu não entendo saída desse estilo:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <xsl:apply-templates select="root/sub"/>
    </xsl:template>

    <xsl:template match="sub">
        <xsl:variable name="seq">
            <xsl:sequence select="*" />
        </xsl:variable>

        <xsl:message>
            <xsl:value-of select="@id" />
            <xsl:text>: </xsl:text>
            <xsl:value-of select="count($seq)" />
        </xsl:message>
    </xsl:template>
</xsl:stylesheet>

quando aplicada a seguinte XML:

<root>
    <sub id="empty" />
    <sub id="one"><one/></sub>
    <sub id="two"><one/><one/></sub>
    <sub id="three"><one/><one/><one/></sub>
</root>

Saída, escrito por elemento xsl:message, é:

empty: 1
one: 1
two: 1
three: 1

Eu esperava este em vez disso:

empty: 0
one: 1
two: 2
three: 3

Por que count($seq) sempre retornar 1 neste caso? Como você mudaria definição de variável, para que eu possa depois testá-lo para o vazio? (<xsl:variable name='seq' select='*' /> simples voltaria resposta esperada, mas não é uma opção ... Eu quero variável mudança between em este modelo , e testá-lo para o vazio mais tarde).

Foi útil?

Solução

Deixe-me tentar responder o "porquê" parte da sua pergunta.

Se você escrever a seguinte declaração:

<xsl:variable name="x" select="*" />

o $x variável contém a sequência dos nós filhos do nó atual. Não há nenhum nó pai implícita na $x, porque você usa select. Agora, considere o seguinte:

<xsl:variable name="x">
    <content />
    <content />
</xsl:variable>

onde $x variável contém uma sequência de um nó: o nó pai de content. Aqui, count($x) sempre lhe dará 1. Para obter a quantidade de elementos content, você precisa para contar os filhos do nó raiz implícita $x:. count($x/content)

Como uma regra de ouro, você pode se lembrar que: se xsl:variable é em si um elemento vazio com um atributo select, o conjunto de resultados será atribuído à variável. Se você usar xsl:variable sem o atributo select, você sempre criar um pai implícita com a variável, e o conteúdo da variável são os filhos debaixo dela .

O mesmo se aplica para o seu exemplo, com xsl:sequence como uma criança a xsl:variable. Por ter um xsl:variable não vazio você cria um pai implícita para a seqüência, que é por isso que você sempre terá 1 se você contar a própria variável.

Se você precisa de ambos: um conjunto de declarações dentro xsl:variable, mas o comportamento do atributo select, você pode resolver isso usando o seguinte:

<xsl:variable name="x" select="$y/*" />

<xsl:variable name="y">
    <xsl:sequence select="foo" />
</xsl:variable>

que passará a produzir a quantidade esperada para count($x), mas se ou não isso é realmente benéficos ou torna seu código mais claro é discutível.

Outras dicas

Ele funciona como você poderia esperar se você quer mudar a declaração de variável para:

<xsl:variable name="seq" select="*"/>

ou declarar o tipo da variável usando 'como' atributo:

<xsl:variable name="seq" as="item()*">
        <xsl:sequence select="*" />
</xsl:variable>

Não especificando qualquer informação do tipo frequentemente Leeds para resultados surpreendentes em XSLT 2.0. Se você estiver usando Saxon, você pode saída como Saxon interpreta a folha de estilo usando a explicar atributo de extensão:

    <xsl:template match="sub" saxon:explain="yes" xmlns:saxon="http://saxon.sf.net/">
    <xsl:variable name="seq">
        <xsl:sequence select="*" />
    </xsl:variable>

    <xsl:message>
        <xsl:value-of select="@id" />
        <xsl:text>: </xsl:text>
        <xsl:value-of select="count($seq)" />
    </xsl:message>
</xsl:template>

Como você pode ver, Saxon constrói um documento de nó fora da seqüência:

Optimized expression tree for template at line 6 in :
                    let $seq[refCount=1] as document-node() :=
                      document-constructor
                        child::element()
                    return
                      message

Você está selecionando os nós sub, e, em seguida, contando cada nó - por isso vai ser sempre 1. Você precisa contar as crianças, por exemplo:

<xsl:value-of select="count($seq/*)" />

lhe dará o resultado que você está esperando.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top