使用XSL分组多个元素

时间:2013-07-03 09:57:43

标签: xml xslt group-by xslt-1.0

我有这样的XML:

<state>
    <current>block</current>
    <next>air</next>
</state>
<state>
    <current>air</current>
    <next>block</next>
</state>
<state>
    <current>air</current>
    <next>swim</next>
</state>
<state>
    <current>block</current>
    <next>air</next>
</state>

所以我想将所有&#34;当前&#34; +&#34; next&#34;我可以遇到的每个当前和下一个不同的元素(使用XSLT 1.0)

air
block
swim

我已经使用了muenchina方法来分组&#34;当前&#34;元素或&#34;下一个&#34;元素,但不是两个在同一时间。

我该怎么办?

2 个答案:

答案 0 :(得分:1)

好吧,事实上它比我预期的要简单。

我只是简单地说:

<xsl:key name="groups" match="//current|//next" use="." />

然后将其用于:

<xsl:template match="current|next" mode="node" >
    <xsl:if test="generate-id() = generate-id(key('groups', normalize-space(.)))">
        <xsl:value-of select="."/>
    </xsl:if>
</xsl:template>

答案 1 :(得分:0)

只需应用已排序的查询并输出唯一的查询:

<xsl:variable name="states">
    <xsl:value-of select="//state/*[contains(name(), 'current next')]/text()"/>
</xsl:variable>

<xsl:for-each select="str:tokenize($states)">
    <xsl:sort select="text()"/>
    <xsl:if test="preceding-sibling::*/text() != text()">
        <xsl:element name="state"><xsl:value-of select="text()"/></xsl:element>
    </xsl:if>
</xsl:for-each>

这是一个更新,其中包含一个使用exsl node-set的示例,用于不支持tokenize的xslt实现:

<xsl:variable name="states">
    <xsl:for-each select="//state/*[contains(name(), 'current next')]">
    <xsl:element name="state">
        <xsl:value-of select="text()"/>
    </xsl:element>
</xsl:variable>

<xsl:for-each select="exsl:node-set($states)/*">
    <xsl:sort select="text()"/>
    <xsl:if test="preceding-sibling::*/text() != text()">
        <xsl:element name="state"><xsl:value-of select="text()"/></xsl:element>
    </xsl:if>
</xsl:for-each>

如果XSLT可以跨多个级别对节点集进行排序,也值得一看。我原先预计这不起作用,但现在不太确定,因为我想知道libxsl是否会先破坏节点集。如果没有,则previous-sibling :: reference将失败,因为它只引用immediate节点,而不是选择的节点:

<xsl:for-each select="//state/*[contains(name(), 'current next')]">
    <xsl:sort select="text()"/>
    <xsl:if test="preceding-sibling::*/text() != text()">
        <xsl:element name="state"><xsl:value-of select="text()"/></xsl:element>
    </xsl:if>
</xsl:for-each>