xml - XSLT for 循环或节点复制的替代方案

标签 xml for-loop iteration xslt-1.0

在我的阅读中,很明显,唯一合理的解决方法是 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/

相关文章:

sql - 如何从 NVARCHAR(MAX) 属性解析编码为 UTF-8 的 XML?

xml - 使用 xpathSApply 在 R 中抓取 XML 属性

java - 如何让 java 程序获取前一个循环的结果并将其输入到同一进程中?

algorithm - 树遍历的迭代方法

c++ - 迭代std::bitset中真实位的有效方法?

c - 删除字符串中的重复项

java - 如何访问 XML 格式的 .txt 文件的值?

c# - 如何在 C# 中针对流安全地创建 XPathNavigator?

javascript - Codility CyclicRotation Javascript 解决方案 : Empty array returns an error

javascript - 列出存储的记录 localStorage |谷歌浏览器扩展