html中补齐table表格合并导致每行td数量不一致的情况

有一个行列合并的表格如下:

|----|-----|-----|-----|
| 华东 | 100 | 120 | 正常 |
| 华东 | 80 | 90 | 正常 |
| 华北 | 150 | 180 | 良好 |
| 合计 || 330 | 390 |

可以看到表格中每行和每列最多有4个td,实际的html源文件中:

第一行有4个td,第二行只有2个td,第三行4个td,第4行3个td,我需要为每一行或者列增加一些隐藏的td,使每一行的td数量一致,修改前的源文件如下:

html 复制代码
<!DOCTYPE html>                                                                                                                                                                                                              
  <html lang="zh-CN">                                                                                                                                                                                                          
  <head>                                                                                                                                                                                                                       
      <meta charset="UTF-8">
      <title></title>                                                                                                                                                                                              
      <style>     
          table {
              border-collapse: collapse;
              width: 100%;
              max-width: 600px;
          }
          td {
              border: 1px solid #333;
              padding: 10px;
              text-align: center;
          }
      </style>
  </head>
  <body>

  <table>
      <tr>
          <td rowspan="2">华东</td>
          <td>100</td>
          <td>120</td>
          <td rowspan="2">正常</td>
      </tr>
      <tr>
          <td>80</td>
          <td>90</td>
      </tr>
      <tr>
          <td>华北</td>
          <td>150</td>
          <td>180</td>
          <td>良好</td>
      </tr>
      <tr>
          <td colspan="2">合计</td>
          <td>330</td>
          <td>390</td>
      </tr>
  </table>

  </body>
  </html>

思路是读取源文件中td的colspan和rowspan属性,在td后面增加若干个带有display:none的td:

java 复制代码
import com.zhou.util.NumberUtil;
import com.zhou.common.model.Point;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.util.*;

/**
 * 表格数据读取转换工具类
 * @author lang.zhou
 * @since  2022/7/25 10:17
 */
@Slf4j
public class TableUtil {






    /**
     * 补齐合并导致每行td数量不一致的情况
     * 添加隐藏td用于占位,降低程序处理逻辑的复杂性
     * @return 返回与某个单元格合并行或列的其他单元格坐标集合
     */
    @SneakyThrows
    public static Map<Point,Set<Point>> fixedTd(Element element){
        int colSize = TableUtil.getColSize(element);
        //读取td的style提供给前端
        Map<Integer, String> tdStyle = new HashMap<>();

        Elements rows = element.select("tr");
        Map<Point,Set<Point>> sameCells = new HashMap<>();

        for (int i = 0; i < rows.size(); i++) {
            Element row = rows.get(i);
            lineY(rows, row, colSize,i,colSize, tdStyle,sameCells);
        }
        return sameCells;
    }

    private static void cellX(Elements rows, Element td, int colSize, int rowIndex, int colIndex, Map<Integer, String> tdStyle, Map<Point,Set<Point>> sameCells){
        Integer rowSpan = NumberUtil.safeToInteger(td.attr("rowspan"), 1);
        Point point = new Point(rowIndex, colIndex);
        Set<Point> points = sameCells.computeIfAbsent(point, l -> new LinkedHashSet<>());
        if(rowSpan > 1){
            for (int k = 1; k < rowSpan; k++) {
                String style = tdStyle.getOrDefault(colIndex + k,"");
                Element nextRow = rows.get(rowIndex + k);
                lineY(rows,nextRow,colSize,rowIndex + k,colIndex,tdStyle,sameCells);
                Element e = new Element("td").attr("style", style + ";display:none");
                e.appendElement("p");
                nextRow.insertChildren(colIndex , e);
                points.add(new Point(rowIndex + k, colIndex));
            }
        }
    }

    private static void lineY(Elements rows,Element row, int colSize, int rowIndex, int to, Map<Integer, String> tdStyle, Map<Point,Set<Point>> sameCells){
        for (int i = 0; i < to; i++) {
            Elements select = row.select("td");
            if (i < select.size()) {
                Element td = select.get(i);
                Point point = new Point(rowIndex, i);
                if(sameCells.containsKey(point)){
                    continue;
                }
                sameCells.computeIfAbsent(point, l -> new LinkedHashSet<>());
                i += cellY(rows,td,colSize,rowIndex,i,tdStyle,sameCells);
            }
        }
    }
    private static int cellY(Elements rows, Element td, int colSize, int rowIndex, int colIndex, Map<Integer, String> tdStyle, Map<Point,Set<Point>> sameCells){
        Integer colSpan = NumberUtil.safeToInteger(td.attr("colspan"), 1);
        Integer rowSpan = NumberUtil.safeToInteger(td.attr("rowspan"), 1);
        String style = tdStyle.get(colIndex);
        Point point = new Point(rowIndex,colIndex);
        Set<Point> pointSet = sameCells.computeIfAbsent(point, l -> new LinkedHashSet<>());
        for (int m = 1; m < colSpan; m++) {
            pointSet.add(new Point(rowIndex,colIndex + m));
            Element e = new Element("td").attr("style", style + ";display:none");
            e.appendElement("p");
            td.after(e);
        }
        for (int n = 0; n < rowSpan; n++) {
            Element row = rows.get(rowIndex + n);
            Elements tds = row.select("td");
            Element nd = tds.get(colIndex);
            cellX(rows,nd,colSize,rowIndex + n,colIndex,tdStyle,sameCells);
        }
        return colSpan - 1;
    }

    /**
     * 得到表格最大列数(考虑合并列)
     */
    public static int getColSize(Element table){
        Element row = table.select("tr").first();
        int cnt = 0;
        Elements cols = row.select("td");
        for (int j = 0; j < cols.size(); j ++) {
            Element td = row.select("td").get(j);
            Integer colSpan = NumberUtil.safeToInteger(td.attr("colspan"), 1);
            cnt += colSpan;
        }
        return cnt;
    }

}

补齐隐藏td后的table源文件如下:

html 复制代码
  <table>
      <tr>
          <td rowspan="2">华东</td>
          <td>100</td>
          <td>120</td>
          <td rowspan="2">正常</td>
      </tr>
      <tr>
          <td style="display: none"></td>
          <td>80</td>
          <td>90</td>
          <td style="display: none"></td>
      </tr>
      <tr>
          <td>华北</td>
          <td>150</td>
          <td>180</td>
          <td>良好</td>
      </tr>
      <tr>
          <td colspan="2">合计</td>
          <td style="display: none"></td>
          <td>330</td>
          <td>390</td>
      </tr>
  </table>
相关推荐
iReachers1 小时前
HTML打包EXE工具四种弹窗方式图文详解 - 单窗口/新窗口/标签页/浏览器打开
前端·javascript·html·弹窗·html打包exe·html转程序
木斯佳2 小时前
前端八股文面经大全:京东零售JDY前端一面(2026-04-14)·面经深度解析
前端·算法·设计模式·ai·断点续传
耗子君QAQ2 小时前
🔧 Rattail | 面向 Vite+ 和 AI Agent 的前端工具链
前端·javascript·vue.js
Bigger2 小时前
面试官问我:“AI 写代码比你快 100 倍,你的价值在哪?”
前端·面试·ai编程
恋恋风尘hhh4 小时前
滑动验证码前端安全研究:以顶象(dingxiang-inc)为例
前端·安全
懂懂tty11 小时前
React状态更新流程
前端·react.js
小码哥_常11 小时前
告别繁琐!手把手教你封装超实用Android原生Adapter基类
前端
skywalk816311 小时前
pytest测试的时候这是什么意思?Migrating <class ‘kotti.resources.File‘>
前端·python
一只蝉nahc11 小时前
vue使用iframe内嵌unity模型,并且向模型传递信息,接受信息
前端·vue.js·unity