每个 XSL 1.0 中的不同值
Distinct-values in XSL 1.0 inside of for each
我想在 for 循环内或某个组内获取不同的值。由于 xsl:key 只能在顶层声明,我如何才能为每个组创建一个 xsl:key?在下面的示例中,该组将是最外层的水果标签。请注意,还有一个 xsl:sort。如果有一种方法可以通过 xpaths(preceding-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>
问题是您希望每个顶级 fruit
元素的 taste
元素都不同。您当前的分组正在获取整个文档的不同元素。
如果您不能更新到 XSLT 2.0,那就流泪吧,因为您必须在 XSLT 1.0 中使用串联键,以包含相关 fruit
元素的唯一标识符,这可以是通过使用 generate-id()
实现
<xsl:key name="taste" use="concat(generate-id(../../..), '|', .)" match="taste" />
然后,在您的 "test" 模板中,定义一个变量来保存相关水果的 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>
我想在 for 循环内或某个组内获取不同的值。由于 xsl:key 只能在顶层声明,我如何才能为每个组创建一个 xsl:key?在下面的示例中,该组将是最外层的水果标签。请注意,还有一个 xsl:sort。如果有一种方法可以通过 xpaths(preceding-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>
问题是您希望每个顶级 fruit
元素的 taste
元素都不同。您当前的分组正在获取整个文档的不同元素。
如果您不能更新到 XSLT 2.0,那就流泪吧,因为您必须在 XSLT 1.0 中使用串联键,以包含相关 fruit
元素的唯一标识符,这可以是通过使用 generate-id()
<xsl:key name="taste" use="concat(generate-id(../../..), '|', .)" match="taste" />
然后,在您的 "test" 模板中,定义一个变量来保存相关水果的 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>