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包含一个节点的序列: 的父节点content。在这里,count($x)永远给你1。要获取content元素的数量,您需要计算$x隐式根节点的子节点:count($x/content)

根据经验,您可以记住:如果xsl:variable本身是一个具有select属性的空元素,则结果集将分配给该变量。如果不使用xsl:variableselect属性,则始终使用该变量创建一个隐式父级,并且该变量的内容是它下​​面的子级

这同样适用于您xsl:sequence小时候的示例 to 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>

不指定任何类型信息通常会在 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
于 2009-11-02T12:08:04.803 回答
2

您正在选择子节点,然后计算每个节点 - 所以它总是 1。您需要计算子节点,例如:

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

会给你你期望的输出。

于 2009-11-01T21:16:21.227 回答