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>
相关推荐
淼澄研学1 小时前
PyTorch深度学习实战:5个核心方法从0到1构建神经网络
前端·数据库·python
MartinYeung51 小时前
[论文学习]WASP:面向提示注入攻击的Web代理安全性基准测试
前端·网络·学习
lemon_sjdk1 小时前
从 ServletRequest 到 Spring 抽象:Web 请求的底层基石与演化
java·前端·spring
程序员黑豆1 小时前
鸿蒙应用开发之状态变化通知:@Watch 装饰器详解与实战
前端·harmonyos
swipe1 小时前
13|(前端转全栈)支付成功不等于结束:回调、幂等、超时关单和状态竞争
前端·后端·面试
swipe1 小时前
12|(前端转全栈)点击提交订单后,后端如何用事务守住价格、库存和订单?
前端·后端·面试
小林ixn1 小时前
React + TypeScript 实战:从“类型体操”到“数据持久化”,一次讲透组件通信与副作用管理
前端·react.js·typescript
何时梦醒1 小时前
React + TypeScript 企业级开发实战:从零搭建到组件架构演进
前端·react.js·全栈
Coffeeee1 小时前
AGP9.0的主要变更项,给Gradle来一次大变样
android·前端·gradle
无人生还2 小时前
从 Vue3 到 React · 快速上手系列第 7 篇:副作用与生命周期 —— watch/watchEffect 如何翻译为 useEffect
前端·vue.js·react.js