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

如何基于嵌套列表数据结构生成带rowspan属性的HTML表格?

问题:嵌套结构生成带rowspan的HTML表格

问题背景

我有如下嵌套列表结构:

class Person {
   public string Name;
   public List<Person> Children;
   public int RowSpan { 
       get 
       { int childrenCount = 0;
          /* 遍历子节点(若存在)更新childrenCount */ 
          return childrenCount == 0 ? 1 : childrenCount;
       }
    };
}

编辑说明: 我的真实数据结构与父子关系无关,仅选用该简单结构便于理解问题。假设每个顶层节点可包含任意数量二级节点,每个二级节点可包含任意数量三级节点,节点不存在跨上级共享归属的情况。
编辑说明2: 我可以轻松获取每个单元格对应的RowSpan值,核心问题是如何在遍历嵌套数据结构的过程中生成正确的HTML表格结构。

数据示例

我构造的结构示例如下:

Person grandpa1  = new Person { Name = "GrandPa1" };
Person grandpa2  = new Person { Name = "GrandPa2" };
Person son1      = new Person { Name = "Son 1" };
Person son2      = new Person { Name = "Son 2" };
Person grandkid1 = new Person { Name = "GrandKid1" };
Person grandkid2 = new Person { Name = "GrandKid2" };
Person grandkid3 = new Person { Name = "GrandKid3" };

grandpa1.Children = new List<Person> { son1, son2 };
son2.Children    = new List<Person> { grandkid1, grandkid2, grandkid3 };

List<Person> family = new List<Person> { grandpa1, grandpa2 } ;

预期效果

我希望将family结构渲染为HTML表格,使用<td rowspan={后代总数量}>实现单元格跨行效果。以上述示例数据为例,预期输出表格效果如下:

.------------------.
|          |       |
|          |  son1 |
|          |-------|-----------.
|          |       | grandkid1 |
| grandpa1 |       |-----------.
|          |       | grandkid2 |
|          |  son2 |-----------.
|          |       | grandkid3 |
|----------|-------.-----------.
| grandpa2 |
.----------.

上述表格中grandpa1的rowspan为4,son2的rowspan为3。对应的HTML代码示例如下:
CSS样式:

table {
  border-collapse: collapse;
}

td, th {
  border: 1px solid black;
  padding: 4px;
}

th
{
  font-family: monospace;
  background-color: #def;
  padding: 0 2em;
}

HTML结构:

<table>
  <thead>
    <tr>
      <th>祖辈</th>
      <th>子辈</th>
      <th>孙辈</th>
    </tr>
  </thead>
  <tr>
    <td rowspan="4"> grandpa1 </td>
    <td> son1 </td>
  </tr>
  <tr>
    <!-- 无需新增grandpa1单元格:渲染中 -->
    <!-- 无需新增son1单元格:渲染完成 -->
    <td rowspan="3"> son2 </td>
    <td> kid1 </td>
  </tr>
  <tr>
    <!-- 无需新增grandpa1单元格:渲染中 -->
    <!-- 无需新增son2单元格:渲染中 -->
    <td> kid2 </td>
  </tr>
  <tr>
    <!-- 无需新增grandpa1单元格:渲染中 -->
    <!-- 无需新增son2单元格:渲染中 -->
    <td> kid3</td>
  </tr>
  <tr>
    <!-- 无需新增grandpa1单元格:渲染完成 -->
    <!-- 无需新增son2单元格:渲染完成 -->
    <td> grandpa2 </td>
  </tr>
</table>

已尝试方案的问题

目前我尝试了多种方案均未成功:

  • 为每个层级单独生成Queue<TagBuilder>,遍历顶层节点时将带对应rowspan的TD元素入队,其余层级同理,最后逐行从各层级队列出队元素拼接为新的TR。但该方案不适用于无子节点的节点,例如son1没有子节点,第三层出队的是son2的子节点,导致结构错乱。
  • 按层级遍历节点,遍历每一级时直接生成带对应rowspan的TD插入TR,但最终生成的表格格式不符合要求。

我可以轻松在Excel中实现该效果,因为Excel支持遍历过程中引用单元格合并状态,可回头为已生成的行追加单元格。请问是否有简单的方案可以基于上述嵌套数据结构生成符合要求的HTML表格?


解决方案

直接用「深度优先遍历+层级剩余行数计数」的方案即可,仅需一次遍历就能完成生成,不需要回溯修改已有内容:

核心思路

  1. 用一个数组记录每一层剩余需要跨行的行数,初始值全为0
  2. 逐行生成<tr>,每一行从最顶层开始判断:
    • 如果当前层剩余行数>0,说明上一个同层级单元格仍处于跨行状态,不需要输出<td>,仅将剩余行数减1
    • 如果剩余行数=0,说明需要输出当前层级的新单元格,取出当前节点的RowSpan赋值给当前层级的剩余行数,输出带rowspan属性的<td>
  3. 遍历到最深层无子节点的节点后,补全当前行剩余空列,闭合<tr>,再处理下一个节点

C#代码实现示例

// 你的场景共3级,总列数为3,可根据实际层级数调整
const int totalLevels = 3;
// 记录每一层剩余跨行的行数
int[] remainingRowspan = new int[totalLevels];
// 存储生成的HTML行内容
List<string> tableRows = new List<string>();

// 深度优先遍历方法,level从0开始计数
void Dfs(List<Person> nodes, int level)
{
    foreach (var node in nodes)
    {
        // 当前层需要输出新td
        if (remainingRowspan[level] == 0)
        {
            remainingRowspan[level] = node.RowSpan;
            string td = $"<td rowspan=\"{node.RowSpan}\">{node.Name}</td>";
            // 顶层节点对应新行开头
            if (level == 0)
            {
                tableRows.Add("<tr>" + td);
            }
            else
            {
                tableRows[^1] += td;
            }
        }
        // 剩余跨行计数减1
        remainingRowspan[level]--;
        
        // 存在子节点则递归遍历下一层
        if (node.Children?.Any() == true)
        {
            Dfs(node.Children, level + 1);
        }
        else
        {
            // 无子节点,补全当前行剩余列的计数,闭合行
            for (int i = level + 1; i < totalLevels; i++)
            {
                remainingRowspan[i]--;
            }
            tableRows[^1] += "</tr>";
        }
    }
}

// 调用生成表格
Dfs(family, 0);

// 拼接完整HTML代码
string finalTable = $@"
<table>
  <thead>
    <tr>
      <th>祖辈</th>
      <th>子辈</th>
      <th>孙辈</th>
    </tr>
  </thead>
  <tbody>
    {string.Join("\n", tableRows)}
  </tbody>
</table>";

效果验证

代入你提供的示例数据运行上述代码,最终生成的HTML结构完全符合预期,grandpa1的rowspan为4、son2的rowspan为3,单元格跨行逻辑和示例完全一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.12 22:06:02