在我的阅读中,很明显,唯一合理的解决方法是 for i .. m
XSLT 1.0 中的循环使用递归模板。
除非有人可以另外解释,否则似乎考虑到 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
属性在输入文档的元素中很常见,其语义意图正如我上面的示例所描述的。
如果我要使用递归迭代器方法,我必须将其烘焙到每个模板中(这将非常不干;更像是非常湿,如“为什么还要尝试”;但我离题)
如果有创建通用的策略for
模板,可以使用它执行任何转换操作,这将是非常壮观的。如果我可以在不使用任何递归迭代器的情况下逃脱,如果用于此目的的函数的某些精华隐藏在 XSLT 1.0 中,那将同样令人惊叹。
无论如何,我怎样才能做到这一点?我是否需要采用 WET 方法,还是有更好的方法?
最佳答案
递归没有任何问题。对于这种情况,使其足够通用应该很容易。
这是一个例子。除了输出与 count
相同的数字的子元素之外,我还将 name
元素更改为 new_elem
(只是为了显示额外的转换)。 ..
XSLT 1.0
<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>
关于xml - XSLT for 循环或节点复制的替代方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16160768/