我有一个名为filt
的变量,它包含一个像这样的xml:
<filters>
<ISP_WebItem FILTER="Farve" FILTERNAME="Transparent" UNITCODE="" />
<ISP_WebItem FILTER="Antal" FILTERNAME="10" UNITCODE="mapper" />
<ISP_WebItem FILTER="Indpakning" FILTERNAME="Æske" UNITCODE="" />
<ISP_WebItem FILTER="Materiale" FILTERNAME="PP" UNITCODE="" />
<ISP_WebItem FILTER="Bredde" FILTERNAME="35.6" UNITCODE="cm" />
<ISP_WebItem FILTER="Farve" FILTERNAME="blue" UNITCODE="" />
<ISP_WebItem FILTER="Dybde" FILTERNAME="5" UNITCODE="mm" />
<ISP_WebItem FILTER="Farve" FILTERNAME="red" UNITCODE="" />
</filters>
我想按其'FILTER'属性对这些元素进行分组。也就是说,我想要这样的输出xml(请注意,xml元素是通过过滤器属性重新排列的,即所有带有filter的元素现在都在相邻位置)
<filters>
<ISP_WebItem FILTER="Farve" FILTERNAME="Transparent" UNITCODE="" />
<ISP_WebItem FILTER="Farve" FILTERNAME="blue" UNITCODE="" />
<ISP_WebItem FILTER="Farve" FILTERNAME="red" UNITCODE="" />
<ISP_WebItem FILTER="Antal" FILTERNAME="10" UNITCODE="mapper" />
<ISP_WebItem FILTER="Indpakning" FILTERNAME="Æske" UNITCODE="" />
<ISP_WebItem FILTER="Materiale" FILTERNAME="PP" UNITCODE="" />
<ISP_WebItem FILTER="Bredde" FILTERNAME="35.6" UNITCODE="cm" />
<ISP_WebItem FILTER="Dybde" FILTERNAME="5" UNITCODE="mm" />
</filters>
我试过这样做:
<xsl:variable name="grouped_filt" select="$filt//ISP_WebItem[@FILTER = preceding-sibling::*[1]/@FILTER ]"></xsl:variable>
但是没有用。我看不出有什么不对。有人能帮忙吗?
XSLT 1.0中的标准方法称为Muenchian Grouping:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output method="xml" indent="yes" />
<xsl:key name="itemByFilter" match="ISP_WebItem" use="@FILTER" />
<xsl:template match="filters">
<filters>
<xsl:apply-templates select="ISP_WebItem[
generate-id() = generate-id(key('itemByFilter', @FILTER)[1])]" />
</filters>
</xsl:template>
<xsl:template match="ISP_WebItem">
<xsl:copy-of select="key('itemByFilter', @FILTER)" />
</xsl:template>
</xsl:stylesheet>
generate-id() = generate-id(key('itemByFilter', @FILTER)[1])
是一种方法,只选择第一个 ISP_WebItem
元素与每个FILTER
值,并将ISP_WebItem
模板应用到该元素。然后在模板中复制所有具有相同FILTER
值的元素。
你说<filters>
元素是在一个"名为filt的变量",而不是你直接从输入文档匹配的东西。在这种情况下,您可以使用相同的键定义
<xsl:key name="itemByFilter" match="ISP_WebItem" use="@FILTER" />
但是用<xsl:for-each select="$filt/filters">
代替<xsl:template match="filters">
。如果filt
变量是一个结果树片段而不是一个节点集——也就是说,它被创建为
<xsl:variable name="filt">
<filters>
<!-- ... -->
</filters>
</xsl:variable>
,您将需要一个扩展函数将其转换回节点集
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:exslt="http://exslt.org/common"
exclude-result-prefixes="exslt">
<xsl:strip-space elements="*"/>
<xsl:output method="xml" indent="yes" />
<xsl:key name="itemByFilter" match="ISP_WebItem" use="@FILTER" />
<xsl:variable name="filt">
<filters>
<ISP_WebItem FILTER="Farve" FILTERNAME="Transparent" UNITCODE="" />
<ISP_WebItem FILTER="Antal" FILTERNAME="10" UNITCODE="mapper" />
<ISP_WebItem FILTER="Farve" FILTERNAME="blue" UNITCODE="" />
</filters>
</xsl:variable>
<xsl:variable name="grouped_filt">
<xsl:for-each select="exslt:node-set($filt)/filters">
<filters>
<xsl:apply-templates select="ISP_WebItem[
generate-id() = generate-id(key('itemByFilter', @FILTER)[1])]" />
</filters>
</xsl:for-each>
</xsl:variable>
<xsl:template match="/">
<!-- Demonstrate that the grouping did the right thing -->
<xsl:copy-of select="$grouped_filt" />
</xsl:template>
<xsl:template match="ISP_WebItem">
<xsl:copy-of select="key('itemByFilter', @FILTER)" />
</xsl:template>
</xsl:stylesheet>
这个样式表在运行任何输入文档(例如<foo/>
)时将输出
<?xml version="1.0"?>
<filters>
<ISP_WebItem FILTER="Farve" FILTERNAME="Transparent" UNITCODE=""/>
<ISP_WebItem FILTER="Farve" FILTERNAME="blue" UNITCODE=""/>
<ISP_WebItem FILTER="Antal" FILTERNAME="10" UNITCODE="mapper"/>
</filters>