XSLT сортирует xml на основе значений, которые должны вычисляться динамически

Мне нужно отсортировать файл xml на основе нескольких значений. Входной xml имеет следующую структуру:

<DataSet>
<Product>
    <Category>100</Category>
    <ProductGroup>2000</ProductGroup>
    <ProductNr>30003</ProductNr>
</Product>  
<Product>
    <Category>100</Category>
    <ProductGroup>2000</ProductGroup>
    <ProductNr>30001</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>30006</ProductNr>
</Product>
<Product>
    <Category>200</Category>
    <ProductGroup>4000</ProductGroup>
    <ProductNr>30009</ProductNr>
</Product>
<Product>
    <Category>200</Category>
    <ProductGroup>4000</ProductGroup>
    <ProductNr>30007</ProductNr>
</Product>
<Product>
    <Category>200</Category>
    <ProductGroup>3000</ProductGroup>
    <ProductNr>30005</ProductNr>
</Product>

This xml should be sorted by Category, then by ProductNr but grouped by ProductGroup. That means, if in ProductGroup 2000 there is a Product with a smaller ProductNr than in ProductGroup 1000, then ProductGroup 2000 should be printed befor ProductGroup 1000.

Выходной xml должен выглядеть так:

<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>

Now my idea ist to generate an key for sorting purpose based on the following logic: key = Category + (smallest ProductNr in ProductGroup) + ProductNr

Затем я могу отсортировать по этому ключу и получить правильный результат.

Я новичок в XSLT и не знаю, как вычислить наименьший ProductNr в ProductGroup, а затем отсортировать по этому значению. Можете ли вы дать мне подсказку?

Или: есть ли лучшая технология для решения этой задачи?


person Christian Fries    schedule 18.03.2013    source источник


Ответы (1)


Это должно сделать это:

<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>
person JLRishe    schedule 18.03.2013