3

このスタイルシートからの出力がわかりません。

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

次のXMLに適用した場合:

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

xsl:message要素によって記述された出力は次のとおりです。

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

私は代わりにこれを期待しました:

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

この場合、なぜcount($seq)常に1を返すのですか?後で空をテストできるように、変数の定義をどのように変更しますか?(単純な<xsl:variable name='seq' select='*' />場合は期待される答えが返されますが、オプションではありません...このテンプレートbetweenの変数を変更し、後で空になるかどうかをテストします)。

4

3 に答える 3

5

あなたの質問の「なぜ」の部分に答えてみましょう。

次のステートメントを書く場合:

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

変数$xには、現在のノードの子ノードのシーケンスが含まれます。$xを使用するため、には暗黙の親ノードはありませんselect。ここで、次のことを考慮してください。

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

ここで、変数$xには1つのノードのシーケンスが含まれています:の親ノードcontent。ここでcount($x)は、常にあなたに与えます1。要素の数を取得するには、暗黙のルートノードcontentの子をカウントする必要があります。$xcount($x/content)

経験則として、次のことを覚えておいてください。それxsl:variable自体が属性を持つ空の要素であるselect場合、結果セットは変数に割り当てられます。xsl:variable属性なしで使用する場合はselect、常に変数を使用して暗黙の親を作成し、変数の内容はその下の子になります。

xsl:sequence同じことが、子としての例にも当てはまりますxsl:variable。空でないxsl:variableものを使用すると、シーケンスの暗黙の親が作成されます1。そのため、変数自体をカウントすると常に取得されます。

両方が必要な場合:内部にステートメントのバンドルがありxsl:variableますが、属性の動作はselect、次を使用してこれを回避できます。

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

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

これで、の期待される量が得られますがcount($x)、それが本当に有益であるか、コードをより明確にするかどうかは議論の余地があります。

于 2009-11-02T11:15:31.090 に答える
3

変数宣言を次のように変更すると、期待どおりに機能します。

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

または、'as'属性を使用して変数の型を宣言します。

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

タイプ情報を指定しないと、XSLT2.0で驚くべき結果が得られることがよくあります。Saxonを使用している場合は、explain拡張属性を使用してSaxonがスタイルシートをどのように解釈するかを出力できます。

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

ご覧のとおり、Saxonはシーケンスからドキュメントノードを構築します。

Optimized expression tree for template at line 6 in :
                    let $seq[refCount=1] as document-node() :=
                      document-constructor
                        child::element()
                    return
                      message
于 2009-11-02T12:08:04.803 に答える
2

サブノードを選択してから、各ノードをカウントします。したがって、常に1になります。たとえば、子をカウントする必要があります。

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

期待する出力が得られます。

于 2009-11-01T21:16:21.227 に答える