使用kicker通过XSLT创建聚合节点

时间:2011-09-28 03:40:22

标签: xml xslt recursion

我在xsl中思考不好,所以我无法理解如何处理这个问题。我需要汇总数量,但要按父节点中属性的id进行分组。我认为这应该是一个非常简单的递归模板,但我无法将它抽出来

此输入xml如下所示:

<foo>
  <lines>
    <line line_id="10000">
      <qty>10</qty>
    </line>
    <line line_id="10000">
      <qty>4</qty>
    </line>
    <line line_id="10000">
      <qty>12</qty>
    </line>
    <line line_id="20000">
      <qty>1</qty>
    </line>
    <line line_id="30000">
      <qty>4</qty>
    </line>
    <line line_id="30000">
      <qty>6</qty>
    </line>
  </lines>
  <lines>
    <line line_id="10000">
      <qty>4</qty>
    </line>
  </lines>
</foo>

输出应为:

<newfoo>
  <items>
    <item>
      <item_id>10000</item_id>
      <quantity>26</quantity>
    </item>
    <item>
      <item_id>20000</item_id>
      <quantity>1</quantity>
    </item>
    <item>
      <item_id>30000</item_id>
      <quantity>10</quantity>
    </item>
  </items>
  <items>
    <item>
      <item_id>10000</item_id>
      <quantity>4</quantity>
    </item>
  </items>
</newfoo>

1 个答案:

答案 0 :(得分:0)

这可以通过使用名为Muenchian Grouping的方法在XSLT1.0中实现。

首先,使用 line_id 属性作为键,定义一个键,以查找给定元素的元素。因此,对于给定的line元素和line_id属性,将返回所有匹配的 line 元素。你需要一个连锁密钥。

<xsl:key name="id" 
   match="line" 
   use="concat(concat(generate-id(..), ','), @line_id)"/>

接下来,您需要匹配在元素中首次出现每个不同 line_id 属性的元素。这是通过以下方式实现的:

<xsl:apply-templates 
  select="line[
    generate-id() = 
    generate-id(key('id',concat(concat(generate-id(..),','),@line_id))[1])]" />

即。匹配元素,这些元素恰好是给定键列表中的第一个元素。

然后,您只需将关键字中的所有元素相加

即可获得总数量
<xsl:value-of 
  select="sum(key('id', concat(concat(generate-id(..), ','), @line_id))/qty)"/>

以下是完整的XSLT文档:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>

   <xsl:key name="id" match="line" use="concat(concat(generate-id(..), ','), @line_id)"/>

   <xsl:template match="/foo">
      <newfoo>
         <xsl:apply-templates select="lines"/>
      </newfoo>
   </xsl:template>

   <xsl:template match="lines">
      <items>
         <xsl:apply-templates select="line[generate-id() = generate-id(key('id', concat(concat(generate-id(..), ','), @line_id))[1])]"/>
      </items>
   </xsl:template>

   <xsl:template match="line">
      <item>
         <item_id>
            <xsl:value-of select="@line_id"/>
         </item_id>
         <quantity>
            <xsl:value-of select="sum(key('id', concat(concat(generate-id(..), ','), @line_id))/qty)"/>
         </quantity>
      </item>
   </xsl:template>
</xsl:stylesheet>

应用于以下XML时:

<foo>
   <lines>
      <line line_id="10000">
         <qty>10</qty>
      </line>
      <line line_id="10000">
         <qty>4</qty>
      </line>
      <line line_id="10000">
         <qty>12</qty>
      </line>
      <line line_id="20000">
         <qty>1</qty>
      </line>
      <line line_id="30000">
         <qty>4</qty>
      </line>
      <line line_id="30000">
         <qty>6</qty>
      </line>
   </lines>
   <lines>
      <line line_id="10000">
         <qty>4</qty>
      </line>
   </lines>
</foo>

输出以下XML:

<newfoo>
   <items>
      <item>
         <item_id>10000</item_id>
         <quantity>26</quantity>
      </item>
      <item>
         <item_id>20000</item_id>
         <quantity>1</quantity>
      </item>
      <item>
         <item_id>30000</item_id>
         <quantity>10</quantity>
      </item>
   </items>
   <items>
      <item>
         <item_id>10000</item_id>
         <quantity>4</quantity>
      </item>
   </items>
</newfoo>