有一个行列合并的表格如下:
|----|-----|-----|-----|
| 华东 | 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>