需求:
- 完成excel表格内容转json,excel表格内可能存在多个表格,要求全部解析出来。
- 完成表格内合服功能,即:提取表格内老服务器与新服务器数据,多台老服务器对应合并到一台新服务器上
3.最终输出结果为:[{‘10086-l’:[‘10086-1’,‘10086-2’,…]}] …
一、前置准备
安装依赖
首先确保安装 xlsx 库:
npm install xlsx
核心思路
嵌套表格通常通过空行、固定标题或特定标识分隔,且子表格结构一致(如列数、表头相同)。需通过遍历行数据,识别子表格的边界(起始行、结束行),再提取每个子表格的内容并转换为 JSON。
二、实现步骤及代码
假设 Excel 结构如下(示例):
包含 3 个子表格,以空行分隔,每个子表格有表头(name、id、老服务器,新服务器)和数据行。
1. 读取 Excel 文件并解析工作表
return new Promise((resolve, reject) => {
const reader = new FileReader();
// 开始读取文件内容
reader.readAsArrayBuffer(raw);
reader.onload = (e) => {
// 将文件内容读取为ArrayBuffer并解析为workbook对象
const data = e.target?.result;
// 第一行开始 第五行结束
const workbook = XLSX.read(data, { type: "array" });
// 获取第一个工作表数据并转换为JSON格式
const sheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[sheetName];
const rows = XLSX.utils.sheet_to_json(worksheet, {
header: 1,
raw: false, // 保留原始值(字符串)
});
};
// 处理文件读取错误
reader.onerror = (error) => {
reject(error);
};
});
2. 识别子表格边界
通过空行(元素全为 undefined 或空字符串)分隔子表格,记录每个子表格的起始行和结束行:
// 存储所有子表格的范围:{ start: 行索引, end: 行索引 }
const tableRanges = [];
let currentStart = null;
// 遍历所有行,识别子表格边界
for (let i = 0; i < rows.length; i++) {
const row = rows[i];
// 判断是否为空行(过滤全空或仅含空字符串的行)
const isEmptyRow = row.every(cell => cell === undefined || cell === null || cell === '');
if (!isEmptyRow) {
// 非空行:若未记录起始行,则标记为子表格开始
if (currentStart === null) {
currentStart = i;
}
} else {
// 空行:若已记录起始行,则标记为子表格结束
if (currentStart !== null) {
tableRanges.push({ start: currentStart, end: i - 1 });
currentStart = null;
}
}
}
// 处理最后一个子表格(若文件末尾无空行)
if (currentStart !== null) {
tableRanges.push({ start: currentStart, end: rows.length - 1 });
}
3. 提取子表格数据并转换为 JSON
假设每个子表格的第一行为表头,后续为数据行:
// 存储最终结果:键为子表格索引,值为数据数组
// 存储最终结果:键为子表格索引,值为数据数组
const result = [];
tableRanges.forEach((range, tableIndex) => {
const { start, end } = range;
// 表头行(子表格起始行)
const headers = rows[start].filter(cell => cell !== undefined && cell !== ''); // 过滤空单元格
// 数据行(从表头下一行到结束行)
const tableData = [];
for (let i = start + 1; i <= end; i++) {
const row = rows[i];
const rowData = {};
// 映射表头与数据(忽略超出表头列数的单元格)
headers.forEach((header, colIndex) => {
rowData[header] = row[colIndex] || ''; // 空单元格用空字符串代替
});
tableData.push(rowData);
}
tableData.forEach(rowData => {
if (rowData.newServer) {
}
});
let data = transformServers(tableData)
if (Object.keys(data).length) {
result.push(data)
}
});
三、关键处理说明
1. 边界识别优化
若子表格通过特定标题(如 “表格 1 开始”)分隔,可修改空行判断逻辑,例如:
// 假设子表格以 "表格x" 开头
const isTableHeader = row[0]?.startsWith('表格');
if (isTableHeader) { /* 标记子表格开始 */ }
- 合并单元格处理
若存在合并单元格,xlsx 会仅在合并区域的首个单元格保留值,其他为 undefined。可通过以下方式填充合并单元格数据:
// 先获取合并单元格信息
const merges = worksheet['!merges'] || [];
// 遍历合并区域,复制首个单元格的值到其他位置
merges.forEach(merge => {
const { s, e } = merge; // s: 起始行/列, e: 结束行/列
const value = rows[s.r][s.c];
for (let r = s.r; r <= e.r; r++) {
for (let c = s.c; c <= e.c; c++) {
rows[r][c] = value;
}
}
});
数据类型转换
默认输出为字符串,可根据需求自行格式化
function transformServers(servers) {
const result = {};
let currentNewServer = null;
let keys = Object.keys(servers[0]);
for (const serverInfo of servers) {
// 如果当前项有newServer值,更新当前newServer
if (serverInfo[keys[3]]) {
currentNewServer = serverInfo[keys[3]];
// 初始化数组并添加当前server
result[currentNewServer] = [serverInfo[keys[2]]];
}
// 如果当前有活跃的newServer且当前项没有newServer,添加到数组
else if (currentNewServer) {
result[currentNewServer].push(serverInfo[keys[2]]);
}
}
return result;
}
四、页面代码部分
<template>
<el-dialog
title="提示"
:visible.sync="dialogVisible"
width="500"
:before-close="handleClose">
<el-upload
class="upload-demo"
drag
action="''"
:multiple="false"
:auto-upload="false"
:file-list="fileList"
:on-change="handleChange"
:on-remove="beforeUpload"
ref="upload"
:limit="1"
accept=".xlsx,.xls"
>
<i class="el-icon-upload"></i>
<div class="el-upload__text">
<div>将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip">
上传excel文件,请勿超过5M,每次最多只能上传1个文件
</div>
</div>
</el-upload>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="toJson">tojson</el-button>
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="dialogVisible = false">确 定</el-button>
</span>
</el-dialog>
</template>
<script>
import {excelToJson} from '../../../utils/excel2json'
export default {
data() {
return {
dialogVisible: false,
fileList: [],
};
},
methods: {
handleChange(file, fileList){
console.log(fileList,file,'---');
this.fileList = fileList;
},
beforeUpload(file,fileList){
console.log(fileList,'--');
this.fileList = fileList;
},
handleClose(done) {
this.$confirm('确认关闭?')
.then(_ => {
done();
})
.catch(_ => {});
},
toJson(){
console.log(this.fileList);
excelToJson(this.fileList[0].raw)
}
},
};
</script>
<style lang="scss">
.upload-demo{
.el-upload {
width:100%;
}
.el-upload-dragger{
width:100%;
}
width:100%;
}
</style>
五、总结
通过上述步骤,可实现对嵌套规律表格的解析:
读取 Excel 并转换为行数组;
根据空行或特定标识识别子表格范围;
提取每个子表格的表头和数据,映射为 JSON 对象;
按需处理合并单元格和数据类型。
根据实际 Excel 结构,只需调整边界识别逻辑和表头映射规则即可适配不同场景。