如何基于嵌套列表数据结构生成带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表格?
解决方案
直接用「深度优先遍历+层级剩余行数计数」的方案即可,仅需一次遍历就能完成生成,不需要回溯修改已有内容:
核心思路
- 用一个数组记录每一层剩余需要跨行的行数,初始值全为0
- 逐行生成
<tr>,每一行从最顶层开始判断:- 如果当前层剩余行数>0,说明上一个同层级单元格仍处于跨行状态,不需要输出
<td>,仅将剩余行数减1 - 如果剩余行数=0,说明需要输出当前层级的新单元格,取出当前节点的
RowSpan赋值给当前层级的剩余行数,输出带rowspan属性的<td>
- 如果当前层剩余行数>0,说明上一个同层级单元格仍处于跨行状态,不需要输出
- 遍历到最深层无子节点的节点后,补全当前行剩余空列,闭合
<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
相关产品推荐
相关产品推荐

