首页 > 解决方案 > 每组的 XSLT 最大值

问题描述

我有 xml 中的数据,其中列出了产品及其价格。寻找可以帮助我为每种产品获得最高价格的 XSLT。尝试了可能的事情,但没有运气。请帮忙。

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <Product>
    <name>P1</name>
    <price>10</price>
  </Product>
  <Product>
    <name>P1</name>
    <price>20</price>
  </Product>
  <Product>
    <name>P2</name>
    <price>5</price>
  </Product>
  <Product>
    <name>P3</name>
    <price>8</price>
  </Product>
  <Product>
    <name>P1</name>
    <price>30</price>
  </Product>
</root>

预期产出

Product	Price
P1	30
P2	5
P3	8

标签: xmlxslt

解决方案


使用XSLT 2.0非常简单:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output method="text"/>

  <xsl:template match="root">
    <xsl:text>Product Price&#x0A;</xsl:text>
    <xsl:for-each-group select="Product" group-by="name">
      <xsl:value-of select="concat(current-grouping-key(),
        '      ', max(current-group()/price), '&#x0A;')"/>
    </xsl:for-each-group>
  </xsl:template>
</xsl:transform>

如您所见,需要一个for-each-group循环,选择Product元素并根据子name元素的值对它们进行分组。

在循环内部,current-grouping-key()函数提供当前组的键(name元素的值)并max(current-group()/price)计算最大价格。

有关工作示例,请参见http://xsltransform.net/pNEhB3c

按照您对 XSLT 版本的评论进行编辑

您的任务也可以在XSLT 1.0中完成,使用所谓的 Muenchian Grouping(有关更详细的描述,请在 Web 上搜索)。

首先要做的是创建一个key,将要分组的元素(Product)放在某个分组键(在我们的例子中 为 name)下:

<xsl:key name="prods" match="Product" use="name"/>

然后可以在for-each循环中执行实际的分组,使用带有Muenchian Grouping 习语的谓词:

[generate-id()=generate-id(key('prods', name)[1])]

另一个难点是XSLT 1.0的功能非常有限,甚至没有max功能。

为了规避这个限制,我们必须编写一个模板 (我称之为最大值),它接受一系列元素,对它们进行排序(降序)并输出第一个(最大值)值。

为当前组price中所有 元素的子元素调用此模板。Product

所以整个脚本如下所示:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="text"/>
  <xsl:key name="prods" match="Product" use="name"/>

  <xsl:template match="root">
    <xsl:text>Product Price&#x0A;</xsl:text>
    <xsl:for-each select="Product[generate-id()=
      generate-id(key('prods', name)[1])]">
      <xsl:value-of select="concat(name, '      ')"/>
      <xsl:call-template name="maximum">
        <xsl:with-param name="src" select="key('prods', name)/price"/>
      </xsl:call-template>
      <xsl:value-of select="'&#x0A;'"/>
    </xsl:for-each>
  </xsl:template>

 <xsl:template name="maximum">
    <xsl:param name="src"/>
    <xsl:for-each select="$src">
      <xsl:sort select="." data-type="number" order="descending"/>
      <xsl:if test="position()=1">
        <xsl:value-of select="."/>
      </xsl:if>
    </xsl:for-each>
  </xsl:template>
</xsl:transform>

有关工作示例,请参见http://xsltransform.net/pNEhB3c/1


推荐阅读