在处理XML数据时,经常需要对元素进行分组和汇总。例如,可能需要根据团队ID将员工的工作时间进行汇总。本文将介绍如何使用XSLT技术实现这一目标。
首先,来看一个XML示例,其中包含了员工的详细信息,包括团队ID、任务ID、工作时间、员工ID、姓名和姓氏。
<?xml version="1.0"?>
<Employees>
<Employee>
<TeamID>1</TeamID>
<TeamName>Sales</TeamName>
<TaskID>1</TaskID>
<Hours>5</Hours>
<EmployeeID>1</EmployeeID>
<Name>Bob</Name>
<Surname>Shibob</Surname>
</Employee>
...
</Employees>
如果想要按团队ID对员工的工作时间进行汇总,一种方法是遍历每个<Employee>元素,但这种方法效率低下,因为它需要跟踪前一个元素的ID。
更高效的方法是使用Muenchian方法,即通过构建一个唯一键的列表,然后使用这些键来分组结果。首先,需要定义用于分组<Employee>元素的键,包括团队ID和员工ID。
<xsl:key name="keyTeamID" match="Employee" use="TeamID"/>
<xsl:key name="keyEmployeeID" match="Employee" use="EmployeeID"/>
接下来,选择每个团队的第一个元素,并将该团队的所有<Employee>元素保存到一个变量中。
<xsl:for-each select="//Employee[generate-id(.) = generate-id(key('keyTeamID', TeamID)[1])]">
<xsl:variable name="lngTeamID">
<xsl:value-of select="TeamID"/>
</xsl:variable>
<xsl:variable name="lstEmployee" select="//Employee[TeamID=$lngTeamID]"/>
现在,需要将这个列表中的<Employee>元素按员工ID进行分组。这与按团队ID分组类似,不同之处在于,这次只需要从变量中选择元素,而不需要从整个结果集中选择元素。
<xsl:for-each select="$lstEmployee[generate-id(.) = generate-id(key('keyEmployeeID', EmployeeID)[1])]">
最后,可以轻松地显示每个员工的总工作时间。
<xsl:value-of select="sum($lstEmployee[EmployeeID=$lngEmployeeID]/Hours)"/>
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="keyTeamID" match="Employee" use="TeamID"/>
<xsl:key name="keyEmployeeID" match="Employee" use="EmployeeID"/>
<xsl:template match="/">
<html>
<head>
<title>Employee Hours By Team</title>
<link type="text/css" rel="stylesheet" href="groupxml.css"/>
</head>
<body>
<h3>Employee Hours By Team</h3>
<table>
<xsl:for-each select="//Employee[generate-id(.) = generate-id(key('keyTeamID', TeamID)[1])]">
<xsl:variable name="lngTeamID">
<xsl:value-of select="TeamID"/>
</xsl:variable>
<xsl:variable name="lstEmployee" select="//Employee[TeamID=$lngTeamID]"/>
<xsl:call-template name="ShowEmployeesInTeam">
<xsl:with-param name="lstEmployee" select="$lstEmployee"/>
</xsl:call-template>
</xsl:for-each>
<tr>
<td colspan="4" class="RightJustified DarkBack">Grand Total</td>
<td colspan="1" class="RightJustified DarkBack">
<xsl:value-of select="sum(//Employee/Hours)"/>
</td>
</tr>
</table>
</body>
</html>
</xsl:template>
<xsl:template name="ShowEmployeesInTeam">
<xsl:param name="lstEmployee"/>
<tr>
<td colspan="4" class="DarkBack">
<xsl:value-of select="$lstEmployee[1]/TeamName"/>
</td>
<td colspan="1" class="DarkBack RightJustified">HOURS</td>
</tr>
<xsl:for-each select="$lstEmployee[generate-id(.) = generate-id(key('keyEmployeeID', EmployeeID)[1])]">
<xsl:variable name="lngEmployeeID" select="EmployeeID"/>
<tr>
<td colspan="4">
<xsl:value-of select="$lstEmployee[EmployeeID=$lngEmployeeID]/Name"/>
<xsl:value-of select="$lstEmployee[EmployeeID=$lngEmployeeID]/Surname"/>
</td>
<td colspan="1" class="RightJustified">
<xsl:value-of select="sum($lstEmployee[EmployeeID=$lngEmployeeID]/Hours)"/>
</td>
</tr>
</xsl:for-each>
<tr>
<td colspan="4" class="LightBack RightJustified">Sub-Total</td>
<td colspan="1" class="LightBack RightJustified">
<xsl:value-of select="sum($lstEmployee/Hours)"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>