如何用XSLT按类型统计唯一节点并生成带跨行的HTML表格
XML数据处理与XSLT实现
原始XML结构
<messageList> <message> <type>L1</type> <name>John</name> </message> <message> <type>L2</type> <name>Mary</name> </message> <message> <type>L2</type> <name>John</name> </message> <message> <type>L2</type> <name>John</name> </message> <message> <type>L3</type> <name>Sam</name> </message> <message> <type>L3</type> <name>Tom</name> </message> <message> <type>L3</type> <name>Rob</name> </message> </messageList>
需求说明
需要按type分组统计唯一name的数量,结果要求:
- L1: 1 (John)
- L2: 2 (Mary, John)
- L3: 3 (Sam, Tom, Rob)
最终要生成HTML表格,实现type单元格跨行,每行展示一个唯一name及其在对应type下的出现次数。
当前问题
需要将count(//message[./name=not(.=preceding::*)])与type=$MSGTYPE条件结合,计算每个type对应的唯一name数量,用于设置表格单元格的rowspan属性。当前XSLT代码片段如下:
[....] -------Loop at unique type-------- <xsl:for-each select="//message/type[not(.=preceding::*)]"> <tr> <xsl:variable name="MSGTYPE"> <xsl:value-of select="."/></xsl:variable> -------Rowspan should be number of unique names------- <td rowspan = "{count(//JCOMessage[./JcoServerName=$MSGTYPE and ./MessageName ???not(.=preceding::*)])}"> <xsl:value-of select="."/> </td> [....]
注:代码中JCOMessage、JcoServerName、MessageName应为笔误,对应XML中的message、type、name。
解决方案
1. 正确的唯一name计数XPath
要统计指定type下的唯一name数量,需限定只对比同type下的前置节点,XPath表达式如下:
count(//message[type=$MSGTYPE]/name[not(.=preceding::message[type=$MSGTYPE]/name)])
逻辑说明:
- 先筛选所有
type等于$MSGTYPE的message节点 - 在这些节点的
name中,排除与之前同type节点的name重复的项 - 统计剩余的唯一
name数量
2. 完整XSLT实现代码
以下是生成目标HTML表格的完整XSLT代码,包含跨行设置、唯一name遍历及同名计数:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html" indent="yes"/> <xsl:template match="/"> <html> <body> <table border="1"> <thead> <tr> <th>Type</th> <th>Name</th> <th>Count</th> </tr> </thead> <tbody> <!-- 遍历所有唯一的type --> <xsl:for-each select="//message/type[not(.=preceding::type)]"> <xsl:variable name="currentType" select="."/> <!-- 获取当前type下的唯一name列表 --> <xsl:variable name="uniqueNames" select="//message[type=$currentType]/name[not(.=preceding::message[type=$currentType]/name)]"/> <!-- 遍历每个唯一name --> <xsl:for-each select="$uniqueNames"> <xsl:variable name="currentName" select="."/> <tr> <!-- 仅在第一个name行显示type并设置跨行 --> <xsl:if test="position() = 1"> <td rowspan="{count($uniqueNames)}"> <xsl:value-of select="$currentType"/> </td> </xsl:if> <td><xsl:value-of select="$currentName"/></td> <!-- 统计当前name在该type下的出现次数 --> <td> <xsl:value-of select="count(//message[type=$currentType and name=$currentName])"/> </td> </tr> </xsl:for-each> </xsl:for-each> </tbody> </table> </body> </html> </xsl:template> </xsl:stylesheet>
3. 输出效果
生成的HTML表格如下:
| Type | Name | Count |
|---|---|---|
| L1 | John | 1 |
| L2 | Mary | 1 |
| John | 2 | |
| L3 | Sam | 1 |
| Tom | 1 | |
| Rob | 1 |
内容的提问来源于stack exchange,提问作者Maksim Sirotkin
相关产品推荐
相关产品推荐

