在我的阅读中,很明显,xslt 1.0中for i .. m循环的唯一明智的解决方法是使用递归模板。
除非有人能另外解释,否则进一步看来,由于xslt处理的限制,这种方法一般是不可重用的。
无论如何,给定一个输入片段(在本例中是上下文节点):

<items count="3">
    <item>
        <name>Name</name>
        <description>Description</description>
    </item>
</items>

是否有基于<item>属性复制count子项的可重用策略?这里的预期产出将是
<item>
    <name>Name</name>
    <description>Description</description>
</item>
<item>
    <name>Name</name>
    <description>Description</description>
</item>
<item>
    <name>Name</name>
    <description>Description</description>
</item>

我打算在<item>节点上执行进一步的转换,但是我认为它们不相关。
可重用性是我关心的一个问题,原因很简单,count属性在输入文档的元素中非常常见,语义意图正如我上面的示例所描述的。
如果我要使用递归迭代器方法,我必须将其烘焙到每个模板中(这将非常不干燥;更像是非常潮湿,如“Why even try”;但我偏离了方向)
如果有一种策略来创建一个通用的for模板,使用它可以执行任何转换操作,那将非常壮观。如果我不使用任何递归迭代器就可以离开,如果在xslt 1.0中隐藏了一些用于此目的的函数的精华,那将是同样壮观的。
无论如何,我怎样才能做到这一点?我需要用湿的方法,还是有更好的方法?

最佳答案

递归没有错。在这种情况下,让它足够通用应该很容易。
这里有一个例子。除了输出与count相同的子元素外,我还将name元素更改为new_elem(只是为了显示额外的转换)。
XSLT 1

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="*[@count]">
        <xsl:apply-templates select="*" mode="dupe">
            <xsl:with-param name="count" select="@count"/>
        </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="*" mode="dupe">
        <xsl:param name="count"/>
        <xsl:apply-templates select="."/>
        <xsl:if test="$count > 1">
            <xsl:apply-templates mode="dupe" select=".">
                <xsl:with-param name="count" select="$count - 1"/>
            </xsl:apply-templates>
        </xsl:if>
    </xsl:template>

    <xsl:template match="name">
        <new_elem><xsl:value-of select="."/></new_elem>
    </xsl:template>

</xsl:stylesheet>

输出(使用问题的输入)
<item>
   <new_elem>Name</new_elem>
   <description>Description</description>
</item>
<item>
   <new_elem>Name</new_elem>
   <description>Description</description>
</item>
<item>
   <new_elem>Name</new_elem>
   <description>Description</description>
</item>

如果您可以使用xslt 2.0,您可以像在问题开始时所说的那样迭代:
xslt 2.0(产生与上面相同的输出。如果有多个子元素*[@count],则会略有不同)
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="*[@count]">
        <xsl:variable name="curr" select="."/>
        <xsl:for-each select="1 to @count">
            <xsl:apply-templates select="$curr/*"/>
        </xsl:for-each>
    </xsl:template>

    <xsl:template match="name">
        <new_elem><xsl:value-of select="."/></new_elem>
    </xsl:template>

</xsl:stylesheet>

10-07 19:34
查看更多