You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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表格如下:

TypeNameCount
L1John1
L2Mary1
John2
L3Sam1
Tom1
Rob1

内容的提问来源于stack exchange,提问作者Maksim Sirotkin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 05:07:52