我有一个类似的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>
因此,我想将所有"当前"+"下一个"元素分组,以区分我可能遇到的每个当前和下一个元素(使用XSLT1.0)
air
block
swim
我已经使用muenchina方法对"当前"元素或"下一个"元素进行分组,但不能同时对两者进行分组。
我该如何继续?
好吧,事实上它比我预期的要简单。
我只是简单地放了一个:
<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>
只需应用排序查询并输出唯一的查询:
<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节点集的示例,用于不支持标记化的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是否会首先压平节点集。如果没有,前面的同级::reference将失败,因为它将只引用直接节点,而不是选择中的一个:
<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>