XSLT根据必须动态计算的值对xml进行排序

XSLT根据必须动态计算的值对xml进行排序,xml,sorting,xslt,xslt-grouping,Xml,Sorting,Xslt,Xslt Grouping,我必须根据几个值对xml文件进行排序。输入xml具有以下结构: 100 2000 30003 100 2000 30001 100 1000 30002 100 1000 30004 100 1000 30010 200 3000 30006 200 4000 30009 200 4000 30007 200 3000 30005 此xml应按类别排序,然后按ProductNr排序,但应按ProductGroup分组。这意味着,如果ProductGroup 2000中的ProductNr

我必须根据几个值对xml文件进行排序。输入xml具有以下结构:


100
2000
30003
100
2000
30001
100
1000
30002
100
1000
30004
100
1000
30010
200
3000
30006
200
4000
30009
200
4000
30007
200
3000
30005

此xml应按类别排序,然后按ProductNr排序,但应按ProductGroup分组。这意味着,如果ProductGroup 2000中的ProductNr小于ProductGroup 1000中的ProductNr,则ProductGroup 2000应在ProductGroup 1000之前打印

输出xml应如下所示:


100
2000
30001
100
2000
30003
100
1000
30002
100
1000
30004
100
1000
30010
200
3000
30005
200
3000
30006
200
4000
30007
200
4000
30009

现在,我的想法是根据以下逻辑生成一个用于排序的密钥:
key=Category+(ProductGroup中最小的ProductNr)+ProductNr

然后我可以按此键进行排序并得到正确的结果

我是XSLT新手,不知道如何计算ProductGroup中最小的ProductNr,然后按此值排序。你能给我一个提示吗

或者:是否有更好的技术来解决此任务?

这应该可以:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
  <xsl:key name="kProdInGroup" match="ProductNr" use="../ProductGroup" />

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="/*">
    <xsl:copy>
      <xsl:apply-templates select="Product">
        <!-- First sort by Category -->
        <xsl:sort select="Category" data-type="number" />
        <!-- Then by the min ProductNr per group -->
        <xsl:sort select="key('kProdInGroup', ProductGroup)
                             [not(. &gt; key('kProdInGroup', ../ProductGroup))]"
                  data-type="number" />
        <!-- Then by ProductNr -->
        <xsl:sort select="ProductNr" data-type="number" />
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

应用于示例输入时,结果为:

<DataSet>
  <Product>
    <Category>100</Category>
    <ProductGroup>2000</ProductGroup>
    <ProductNr>30001</ProductNr>
  </Product>
  <Product>
    <Category>100</Category>
    <ProductGroup>2000</ProductGroup>
    <ProductNr>30003</ProductNr>
  </Product>
  <Product>
    <Category>100</Category>
    <ProductGroup>1000</ProductGroup>
    <ProductNr>30002</ProductNr>
  </Product>
  <Product>
    <Category>100</Category>
    <ProductGroup>1000</ProductGroup>
    <ProductNr>30004</ProductNr>
  </Product>
  <Product>
    <Category>100</Category>
    <ProductGroup>1000</ProductGroup>
    <ProductNr>30010</ProductNr>
  </Product>
  <Product>
    <Category>200</Category>
    <ProductGroup>3000</ProductGroup>
    <ProductNr>30005</ProductNr>
  </Product>
  <Product>
    <Category>200</Category>
    <ProductGroup>3000</ProductGroup>
    <ProductNr>30006</ProductNr>
  </Product>
  <Product>
    <Category>200</Category>
    <ProductGroup>4000</ProductGroup>
    <ProductNr>30007</ProductNr>
  </Product>
  <Product>
    <Category>200</Category>
    <ProductGroup>4000</ProductGroup>
    <ProductNr>30009</ProductNr>
  </Product>
</DataSet>

100
2000
30001
100
2000
30003
100
1000
30002
100
1000
30004
100
1000
30010
200
3000
30005
200
3000
30006
200
4000
30007
200
4000
30009
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
  <xsl:key name="kProdInGroup" match="ProductNr" use="../ProductGroup" />

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="/*">
    <xsl:copy>
      <xsl:apply-templates select="Product">
        <!-- First sort by Category -->
        <xsl:sort select="Category" data-type="number" />
        <!-- Then by the min ProductNr per group -->
        <xsl:sort select="key('kProdInGroup', ProductGroup)
                             [not(. &gt; key('kProdInGroup', ../ProductGroup))]"
                  data-type="number" />
        <!-- Then by ProductNr -->
        <xsl:sort select="ProductNr" data-type="number" />
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>
<DataSet>
  <Product>
    <Category>100</Category>
    <ProductGroup>2000</ProductGroup>
    <ProductNr>30001</ProductNr>
  </Product>
  <Product>
    <Category>100</Category>
    <ProductGroup>2000</ProductGroup>
    <ProductNr>30003</ProductNr>
  </Product>
  <Product>
    <Category>100</Category>
    <ProductGroup>1000</ProductGroup>
    <ProductNr>30002</ProductNr>
  </Product>
  <Product>
    <Category>100</Category>
    <ProductGroup>1000</ProductGroup>
    <ProductNr>30004</ProductNr>
  </Product>
  <Product>
    <Category>100</Category>
    <ProductGroup>1000</ProductGroup>
    <ProductNr>30010</ProductNr>
  </Product>
  <Product>
    <Category>200</Category>
    <ProductGroup>3000</ProductGroup>
    <ProductNr>30005</ProductNr>
  </Product>
  <Product>
    <Category>200</Category>
    <ProductGroup>3000</ProductGroup>
    <ProductNr>30006</ProductNr>
  </Product>
  <Product>
    <Category>200</Category>
    <ProductGroup>4000</ProductGroup>
    <ProductNr>30007</ProductNr>
  </Product>
  <Product>
    <Category>200</Category>
    <ProductGroup>4000</ProductGroup>
    <ProductNr>30009</ProductNr>
  </Product>
</DataSet>