每个

时间:2018-06-13 14:46:25

标签: xslt xslt-1.0 msxsl

我想获取for循环内部或某些组内的不同值。由于xsl:key只能在顶层声明,我怎样才能为每个组创建一个xsl:key?在下面的示例中,该组将是最外层的水果标签。请注意,还有一个xsl:sort。如果有办法通过xpaths(previous-sibling)实现这一点,我也很想知道这个解决方案。我不确定我是否需要使用Muenchian方法来实现这一目标,但这就是我所拥有的:

Input.xml中

<root>
<fruits>
    <fruit>
        <fruit id="2">
            <banana><taste>Yummy</taste></banana>
            <banana><taste>Disgusting</taste></banana>
        </fruit>
        <fruit id="1">
            <banana><taste>Eh</taste></banana>
            <banana><taste>Disgusting</taste></banana>
        </fruit>
    </fruit>
    <fruit>
        <fruit id="2">
            <banana><taste>Yummy</taste></banana>
            <banana><taste>Disgusting</taste></banana>
        </fruit>
        <fruit id="1">
            <banana><taste>Amazing</taste></banana>
            <banana><taste>Disgusting</taste></banana>
        </fruit>
    </fruit>    
</fruits>
</root>

Transform.xsl

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:key name="taste" use="." match="taste" />
    <xsl:template match="root">
    <xsl:apply-templates select="fruits" />
    </xsl:template>
    <xsl:template match="fruits">
        <xsl:element name="newFruits">
            <xsl:call-template name="test" />
        </xsl:element>
    </xsl:template>
    <xsl:template name="test">
        <xsl:for-each select="fruit">
        <xsl:sort select="fruit/@id" />
        <xsl:element name="newFruit">
            <!-- xsl:for-each select="fruit/banana/taste[not(.=preceding::taste)]/.." /> -->
            <xsl:for-each select="fruit/banana/taste[generate-id() = generate-id(key('taste',.)[1])]/..">
                <xsl:element name="fruit">
                    <xsl:value-of select="."/>
                </xsl:element>
            </xsl:for-each>
        </xsl:element>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

输出(输出中的注释是应显示的所需标记)

<?xml version="1.0" encoding="UTF-8"?>
<newFruits>
    <newFruit>
        <fruit>Yummy</fruit>
        <fruit>Disgusting</fruit>
        <fruit>Eh</fruit>
    </newFruit>
    <newFruit>
        <!-- <fruit>Yummy</fruit> -->
        <!-- <fruit>Disgusting</fruit> -->
        <fruit>Amazing</fruit>
    </newFruit>
</newFruits>

1 个答案:

答案 0 :(得分:2)

问题在于,您希望每个顶级taste元素的fruit元素都是不同的。您当前的分组是获取整个文档的不同元素。

如果您无法更新到XSLT 2.0,那么您必须在XSLT 1.0中使用连锁密钥,以包含相关fruit元素的唯一标识符,这可以通过使用generate-id()

 <xsl:key name="taste" use="concat(generate-id(../../..), '|', .)" match="taste" />

然后,在“测试”模板中,定义一个变量来保存相关水果的ID ...

 <xsl:variable name="id" select="generate-id()" />

你的表达能够获得独特的品味......

<xsl:for-each select="fruit/banana/taste[generate-id() = generate-id(key('taste', concat($id, '|', .))[1])]">

试试这个XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
    <xsl:output method="xml" indent="yes" />

    <xsl:key name="taste" use="concat(generate-id(../../..), '|', .)" match="taste" />

    <xsl:template match="root">
        <xsl:apply-templates select="fruits" />
    </xsl:template>

    <xsl:template match="fruits">
        <newFruits>
            <xsl:call-template name="test" />
        </newFruits>
    </xsl:template>

    <xsl:template name="test">
        <xsl:for-each select="fruit">
            <xsl:variable name="id" select="generate-id()" />
            <newFruit>
                <!-- xsl:for-each select="fruit/banana/taste[not(.=preceding::taste)]/.." /> -->
                <xsl:for-each select="fruit/banana/taste[generate-id() = generate-id(key('taste', concat($id, '|', .))[1])]">
                    <fruit>
                        <xsl:value-of select="."/>
                    </fruit>
                </xsl:for-each>
            </newFruit>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

注意,你真的不需要第一个模板,我看不到命名模板的要点,所以你可以将上面的XSLT简化为...

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
    <xsl:output method="xml" indent="yes" />

    <xsl:key name="taste" use="concat(generate-id(../../..), '|', .)" match="taste" />

    <xsl:template match="fruits">
        <newFruits>
            <xsl:apply-templates select="fruit" />
        </newFruits>
    </xsl:template>

    <xsl:template match="fruit">
        <xsl:variable name="id" select="generate-id()" />
        <newFruit>
            <!-- xsl:for-each select="fruit/banana/taste[not(.=preceding::taste)]/.." /> -->
            <xsl:for-each select="fruit/banana/taste[generate-id() = generate-id(key('taste', concat($id, '|', .))[1])]">
                <fruit>
                    <xsl:value-of select="."/>
                </fruit>
            </xsl:for-each>
        </newFruit>
    </xsl:template>
</xsl:stylesheet>