xsl:sequence总是非空的吗?

时间:2009-11-01 17:05:01

标签: xslt xpath xslt-2.0 xsl-variable

我不明白这个样式表的输出:

<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='*' />会返回预期答案,但不是一个选项...我想在this template中更改between变量,并稍后对其进行空虚测试。

3 个答案:

答案 0 :(得分:5)

让我试着回答你问题的“为什么”部分。

如果你写下面的陈述:

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

变量$x包含当前节点的子节点的序列。 $x中没有隐式父节点,因为您使用select。现在考虑以下内容:

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

其中变量$x包含一个节点的序列:content的父节点。在此,count($x)将始终为您提供1。要获取content元素的数量,您需要计算$x隐式根节点的子节点:count($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)的预期金额,但这是否真的有益或使您的代码更清晰是有争议的。

答案 1 :(得分:3)

如果您将变量声明更改为:

,它可以正常工作
<xsl:variable name="seq" select="*"/>

或使用'as'属性声明变量的类型:

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

在XSLT 2.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

答案 2 :(得分:2)

您正在选择子节点,然后计算每个节点 - 因此它始终为1.您需要计算子节点,例如:

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

会为您提供您期望的输出。