按属性对XML元素进行分组



我有一个名为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>

相关内容

  • 没有找到相关文章

最新更新