XSLT GROUP BY使用键

时间:2013-03-03 06:15:51

标签: xslt xslt-grouping

我正在尝试生成HTML输出,该输出是以下层次结构上的表--DIVISION,DESK,STRATEGY。我需要在Division列和Desk列上设置rowspan。一个部门可以有多个办公桌,一个办公桌可以有多种策略。

我使用键来分区,桌面定义分组。它适用于分部,但适用于Desk。请指教。

xml代码:

<?xml version="1.0"?>
<ROWSET>
<ROW>
    <DIVISION>Flow Credit</DIVISION>
    <DESK>Europe Indices Net</DESK>
    <ACCT_PNL>     0.18 MM USD</ACCT_PNL>
    <ECO_PNL>     0.00 MM USD</ECO_PNL>
</ROW>
<ROW>
    <DIVISION>Flow Credit</DIVISION>
    <DESK>US CDS Trading</DESK>
    <STRATEGY>Funk_A6M</STRATEGY>
    <ACCT_PNL>    -0.01 MM USD</ACCT_PNL>
    <ECO_PNL>     0.00 MM USD</ECO_PNL>
</ROW>
<ROW>
    <DIVISION>Flow Credit</DIVISION>
    <DESK>US CDS Trading</DESK>
    <STRATEGY>HYQUANTO</STRATEGY>
    <ACCT_PNL>     0.01 MM USD</ACCT_PNL>
    <ECO_PNL>     0.00 MM USD</ECO_PNL>
</ROW>

XSLT:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"   xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="groups" match="/ROWSET/ROW" use="DIVISION"/>
<xsl:key name="groups2" match="/ROWSET/ROW" use="concat(DIVISION, '|', DESK)"/>
<xsl:template match="/ROWSET/ROW">
    <xsl:apply-templates select="result[generate-id() = generate-id(key('groups', DIVISION)[1])]" mode="groups"/>
    <xsl:apply-templates select="result[generate-id() = generate-id(key('groups2', concat(DIVISION, '|', DESK))[1])]" mode="groups2"/>
</xsl:template>
<xsl:template match="/ROWSET">
    <h1>
        <xsl:value-of select="DIVISION"/>
    </h1>
    <table id="{DIVISION}">
        <tr class="heading">
            <th scope="col">DIVISION</th>
            <th scope="col">DESK</th>
            <th scope="col">STRATEGY</th>
        </tr>
        <xsl:for-each select="key('groups', ROW/DIVISION)">
            <tr>
                <xsl:if test="position() = 1">
                    <td valign="center" bgcolor="#999999">
                        <xsl:attribute name="rowspan">  <xsl:value-of select="count(key('groups', DIVISION))"/></xsl:attribute>
                        <b>
                            <xsl:text/>
                            <xsl:value-of select="DIVISION"/>
                        </b>
                    </td>
                </xsl:if>
                <xsl:if test="position() = 1">
                    <td valign="center" bgcolor="#999999">
                        <xsl:attribute name="rowspan">     <xsl:value-of select="count(key('groups2', concat(DIVISION, '|',DESK)))"/></xsl:attribute>
                        <b>
                            <xsl:text/>
                            <xsl:value-of select="DESK"/>
                        </b>
                    </td>
                </xsl:if>
                <td>
                    <xsl:value-of select="STRATEGY"/>
                </td>
            </tr>
        </xsl:for-each>
    </table>
</xsl:template>
</xsl:stylesheet>

1 个答案:

答案 0 :(得分:0)

这有点棘手,但应该这样做:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>
  <xsl:key name="groups" match="/ROWSET/ROW" use="DIVISION"/>
  <xsl:key name="groups2" match="/ROWSET/ROW" use="concat(DIVISION, '|', DESK)"/>

  <xsl:template match="/ROWSET">
    <xsl:apply-templates select="ROW[generate-id() = 
                                     generate-id(key('groups', DIVISION)[1])]" />
  </xsl:template>

  <xsl:template match="ROW">
    <h1>
      <xsl:value-of select="DIVISION"/>
    </h1>
    <table id="{DIVISION}">
      <tr class="heading">
        <th scope="col">DIVISION</th>
        <th scope="col">DESK</th>
        <th scope="col">STRATEGY</th>
      </tr>
      <tr>
        <xsl:call-template name="DivisionCell" />
        <xsl:call-template name="DeskCell" />
        <xsl:call-template name="Strategy" />
      </tr>
      <!-- Remaining rows for the first desk -->
      <xsl:call-template name="DeskRemainder" />
      <!-- Apply templates on the first row of each remaining desk -->
      <xsl:apply-templates 
          select="key('groups', DIVISION)
                    [generate-id() = 
                     generate-id(key('groups2', concat(DIVISION, '|', DESK)
                                 )[1])]
                    [position() > 1]" mode="deskStarter" />
    </table>
  </xsl:template>

  <xsl:template name="DivisionCell">
    <xsl:call-template name="GroupCell">
      <xsl:with-param name="value" select="DIVISION" />
      <xsl:with-param name="key" select="'groups'" />
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="DeskCell">
    <xsl:call-template name="GroupCell">
      <xsl:with-param name="value" select="DESK" />
      <xsl:with-param name="key" select="'groups2'" />
      <xsl:with-param name="keyValue" select="concat(DIVISION, '|', DESK)" />
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="GroupCell">
    <xsl:param name="value" />
    <xsl:param name="key" />
    <xsl:param name="keyValue" select="$value" />

    <td valign="center" bgcolor="#999999"
        rowspan="{count(key($key, $keyValue))}">
      <b>
        <xsl:value-of select="$value"/>
      </b>
    </td>
  </xsl:template>

  <xsl:template name="DeskRemainder">
    <xsl:apply-templates 
            select="key('groups2', concat(DIVISION, '|', DESK))[position() > 1]"
            mode="deskRemainder" />
  </xsl:template>

  <!-- For the first row of each distinct desk, after the first distinct desk -->
  <xsl:template match="ROW" mode="deskStarter">
    <tr>
      <xsl:call-template name="DeskCell" />
      <xsl:call-template name="Strategy" />
    </tr>
    <xsl:call-template name="DeskRemainder" />
  </xsl:template>

  <!-- For remaining rows for a given desk -->
  <xsl:template match="ROW" mode="deskRemainder">
    <tr>
      <xsl:call-template name="Strategy" />
    </tr>
  </xsl:template>

  <xsl:template name="Strategy">
    <td>
      <xsl:value-of select="STRATEGY"/>
    </td>
  </xsl:template>
</xsl:stylesheet>

在此输入XML上运行时(使用额外的项目使其更有趣):

<ROWSET>
  <ROW>
    <DIVISION>Flow Credit</DIVISION>
    <DESK>Europe Indices Net</DESK>
    <ACCT_PNL>     0.18 MM USD</ACCT_PNL>
    <ECO_PNL>     0.00 MM USD</ECO_PNL>
  </ROW>
  <ROW>
    <DIVISION>Flow Credit</DIVISION>
    <DESK>US CDS Trading</DESK>
    <STRATEGY>Funk_A6M</STRATEGY>
    <ACCT_PNL>    -0.01 MM USD</ACCT_PNL>
    <ECO_PNL>     0.00 MM USD</ECO_PNL>
  </ROW>
  <ROW>
    <DIVISION>Other Division</DIVISION>
    <DESK>US CDS Trading</DESK>
    <STRATEGY>HYQUANTO</STRATEGY>
    <ACCT_PNL>     0.01 MM USD</ACCT_PNL>
    <ECO_PNL>     0.00 MM USD</ECO_PNL>
  </ROW>
  <ROW>
    <DIVISION>Flow Credit</DIVISION>
    <DESK>US CDS Trading</DESK>
    <STRATEGY>HYQUANTO</STRATEGY>
    <ACCT_PNL>     0.01 MM USD</ACCT_PNL>
    <ECO_PNL>     0.00 MM USD</ECO_PNL>
  </ROW>
  <ROW>
    <DIVISION>Other Division</DIVISION>
    <DESK>US CDS Trading</DESK>
    <STRATEGY>HYQUANTO</STRATEGY>
    <ACCT_PNL>     0.01 MM USD</ACCT_PNL>
    <ECO_PNL>     0.00 MM USD</ECO_PNL>
  </ROW>
  <ROW>
    <DIVISION>Other Division</DIVISION>
    <DESK>Europe CDS Trading</DESK>
    <STRATEGY>HYQUANTO</STRATEGY>
    <ACCT_PNL>     0.01 MM USD</ACCT_PNL>
    <ECO_PNL>     0.00 MM USD</ECO_PNL>
  </ROW>
</ROWSET>

这会产生:

<h1>Flow Credit</h1>
<table id="Flow Credit">
  <tr class="heading">
    <th scope="col">DIVISION</th>
    <th scope="col">DESK</th>
    <th scope="col">STRATEGY</th>
  </tr>
  <tr>
    <td valign="center" bgcolor="#999999" rowspan="3">
      <b>Flow Credit</b>
    </td>
    <td valign="center" bgcolor="#999999" rowspan="1">
      <b>Europe Indices Net</b>
    </td>
    <td></td>
  </tr>
  <tr>
    <td valign="center" bgcolor="#999999" rowspan="2">
      <b>US CDS Trading</b>
    </td>
    <td>Funk_A6M</td>
  </tr>
  <tr>
    <td>HYQUANTO</td>
  </tr>
</table>
<h1>Other Division</h1>
<table id="Other Division">
  <tr class="heading">
    <th scope="col">DIVISION</th>
    <th scope="col">DESK</th>
    <th scope="col">STRATEGY</th>
  </tr>
  <tr>
    <td valign="center" bgcolor="#999999" rowspan="3">
      <b>Other Division</b>
    </td>
    <td valign="center" bgcolor="#999999" rowspan="2">
      <b>US CDS Trading</b>
    </td>
    <td>HYQUANTO</td>
  </tr>
  <tr>
    <td>HYQUANTO</td>
  </tr>
  <tr>
    <td valign="center" bgcolor="#999999" rowspan="1">
      <b>Europe CDS Trading</b>
    </td>
    <td>HYQUANTO</td>
  </tr>
</table>