Domanda

Non capisco uscita da questo foglio di stile:

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

se applicato a XML seguente:

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

Output, scritto da elemento xsl:message, è:

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

Mi aspettavo questo uno invece:

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

Perché count($seq) sempre ritornare 1 in questo caso? Come cambieresti definizione di variabile, in modo che possa poi testarlo per il vuoto? (Simple <xsl:variable name='seq' select='*' /> sarebbe tornare risposta attesa, ma non è un'opzione ... voglio cambiare variabile between in questo modello e testarlo per il vuoto in seguito).

È stato utile?

Soluzione

Vorrei provare a rispondere al "perché" parte della tua domanda.

Se si scrive la seguente dichiarazione:

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

il $x variabile contiene la sequenza dei nodi figli del nodo corrente. Non c'è nessun nodo padre implicita $x, perché si utilizzano select. Consideriamo ora il seguente:

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

dove $x variabile contiene una sequenza di un nodo: il nodo padre content. Qui, count($x) sarà sempre darà 1. Per ottenere la quantità di elementi content, è necessario contare i figli del nodo radice implicita $x: count($x/content)

.

Come regola generale, si può ricordare che: se xsl:variable è di per sé un elemento vuoto con un attributo select, il set di risultati verrà assegnato alla variabile. Se si utilizza xsl:variable senza l'attributo select, si crea sempre un genitore implicita con la variabile, e il contenuto della variabile siete i figli sotto di esso .

Lo stesso vale per il tuo esempio con xsl:sequence come un bambino a xsl:variable. Avendo un xsl:variable non vuota si crea un genitore implicita per la sequenza, che è il motivo per cui si ottiene sempre 1 se si conta la variabile stessa.

Se avete bisogno di entrambe le cose: un fascio di istruzioni all'interno xsl:variable, ma il comportamento dell'attributo select, è possibile risolvere questo utilizzando il seguente:

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

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

che ora produrrà la quantità prevista per count($x), ma se non che è davvero utile o rende il codice più chiaro è discutibile.

Altri suggerimenti

Funziona come ci si potrebbe aspettare se si sia modificare la dichiarazione variabile:

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

o dichiarare il tipo della variabile usando 'come' attributo:

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

Non specificare le informazioni di tipo spesso Leeds a risultati sorprendenti in XSLT 2.0. Se si utilizza sassone, è possibile uscita come Saxon interpreta il foglio di stile utilizzando l'attributo di estensione spiegare:

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

Come si può vedere, sassone costruisce un documento-nodo di fuori della sequenza:

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

Si sta selezionando i nodi secondari, e poi contando ogni nodo - in modo che sarai sempre 1. È necessario contare i bambini, per esempio:

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

vi darà l'output vi aspettate.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top