XSLT计算,其中分组是关于大孩子的

时间:2012-09-04 14:14:33

标签: xslt xslt-grouping muenchian-grouping

我有一个数据库的XML数据转换,我希望使用xslt呈现。 对于我想要的布局,数据的结构并不“直截了当”(我还将XML数据用于另一个报告)。

我想要的是对Level-A的数据做一些计算,我需要在Level-C的孩子上进行分组。

我知道我可以再次将数据选择到一个XML文件中,其结构对于我的报告来说“简单”,但这是我的最后一招,因为我觉得它也可以在XSLT中完成。最值得探讨的是,我需要一些“Muenchian”技巧才能完成它,但由于我是一个'Muenchian Virgin',我会在每次尝试中陷入困境(我试图'偷'并改变......)。

有人知道Muenchian是否可以继续进行,有人可以帮助我走上正轨吗? 我做了一些阅读(包括Jeni Tennison的),但到目前为止我看到的东西并没有涵盖我的问题,据我所知......

下面是一个简化的XML结构,它(或多或少)代表我的真实问题。

有什么想法吗?

亲切的问候,Henk

简化XML:

<data>
  <a>
    <a_id>A1</a_id>
    <a_desc>A one</a_desc>
    <a_val>1</a_val>
    <b>
      <c>
        <c_id>C2</c_id>
        <c_desc>C two</c_desc>
      </c>
    </b>
  </a>
  <a>
    <a_id>A2</a_id>
    <a_desc>A two</a_desc>
    <a_val>2</a_val>
    <b>
      <c>
        <c_id>C2</c_id>
        <c_desc>C two</c_desc>
      </c>
    </b>
  </a>
  <a>
    <a_id>A3</a_id>
    <a_desc>A three</a_desc>
    <a_val>3</a_val>
    <b>
      <c>
        <c_id>C1</c_id>
        <c_desc>C one</c_desc>
      </c>
    </b>
  </a>
  <a>
    <a_id>A4</a_id>
    <a_desc>A four</a_desc>
    <a_val>7</a_val>
    <b>
      <c>
        <c_id>C3</c_id>
        <c_desc>C three</c_desc>
      </c>
    </b>
  </a>
  <a>
    <a_id>A5</a_id>
    <a_desc>A five</a_desc>
    <a_val>11</a_val>
    <b>
      <c>
        <c_id>C1</c_id>
        <c_desc>C one</c_desc>
      </c>
    </b>
  </a>
</data>

必需的输出应该是:

C_desc  Count() Sum(a_val)  Avg(a_val) 
------  ------- ----------  ----------
C one       3       15          5
C two       1       2           2
C three     1       7           7

1 个答案:

答案 0 :(得分:1)

正如您所提到的,Muenchian分组是可行的方法(在XSLT1.0中)。您说要使用 c 元素中的值对 a 元素进行分组。因此,您可以像这样定义一个键:

<xsl:key name="a" match="a" use="b/c/c_desc" />

然后,您需要获得'distinct' a 元素,这是通过选择恰好是给定键的组中第一个元素的 a 元素来完成的。你用这个相当可怕的表达式

来做到这一点
<xsl:apply-templates 
     select="//a[generate-id() = generate-id(key('a', b/c/c_desc)[1])]" />

在这里,key('a', b/c/c_desc)[1]会找到键组中的第一个元素,然后使用generate-id来比较元素。

然后,您将拥有一个模板来匹配不同的 a 元素,然后您可以在其中对该组进行计算。例如,要获得总和:

<xsl:value-of select="sum(key('a', b/c/c_desc)/a_val)" />

这是完整的XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="exsl">
   <xsl:output method="html" indent="yes"/>
   <xsl:key name="a" match="a" use="b/c/c_desc" />
   <xsl:template match="/">
      <table>
         <tr>
            <td>C_desc</td>
            <td>Count</td>
            <td>Sum</td>
            <td>Avg</td>
         </tr>
      <xsl:apply-templates select="//a[generate-id() = generate-id(key('a', b/c/c_desc)[1])]" />
      </table>
   </xsl:template>

   <xsl:template match="a">
      <xsl:variable name="c_desc" select="b/c/c_desc" />
      <tr>
         <td><xsl:value-of select="count(key('a', $c_desc))" /></td>
         <td><xsl:value-of select="sum(key('a', $c_desc)/a_val)" /></td>
         <td><xsl:value-of select="sum(key('a', $c_desc)/a_val) div count(key('a', $c_desc))" /></td>
      </tr>
   </xsl:template>
</xsl:stylesheet>

当应用于您的示例XML时,输出以下内容

<table>
   <tr>
      <td>C_desc</td>
      <td>Count</td>
      <td>Sum</td>
      <td>Avg</td>
   </tr>
   <tr>
      <td>3</td>
      <td>15</td>
      <td>5</td>
   </tr>
   <tr>
      <td>1</td>
      <td>2</td>
      <td>2</td>
   </tr>
   <tr>
      <td>1</td>
      <td>7</td>
      <td>7</td>
   </tr>
</table>