本文介绍如何在Node.js环境中使用xlsx库读取Excel文件,重点解决合并单元格数据的正确获取问题。通过解析合并区域信息,实现从特定工作表提取表头及结构化数据,并将结果转换为JSON格式输出。
在当前的数据处理场景中,Excel 文件作为广泛使用的数据存储格式,广泛应用于数据分析、报表生成和数据迁移等环节。然而,面对包含合并单元格的 Excel 文件时,数据的提取和处理往往面临一定难度。本文将详细阐述如何利用 Node.js 技术读取 Excel 文件,并有效处理其中的合并单元格问题。

准备工作
首先,需要安装 Node.js 所需的依赖库。本文选用 xlsx 库负责 Excel 文件的读取与解析,同时使用 lodash 库辅助字符串处理。可通过执行以下命令完成库的安装:
npm install xlsx lodash
读取 Excel 文件
第一步是读取目标 Excel 文件。假设文件名为 YD-TP2025-03-22.xlsx,且存放于项目根目录。利用 xlsx.readFile 方法即可实现文件读取:
const xlsx = require('xlsx');
const path = require('path');
const filePath = path.join(__dirname, 'YD-TP2025-03-22.xlsx');
const workbook = xlsx.readFile(filePath);
获取工作表
随后,需从 Excel 文件中提取指定的工作表。假设目标工作表名称为“建设全流程明细”,可通过如下代码获取该工作表对象:
const sheetName = "建设全流程明细";
const sheet = workbook.Sheets[sheetName];
处理合并单元格
Excel 文件中的合并单元格处理是常见难点。通常,合并区域的值仅保留在左上角单元格,其余单元格值为空。为准确获取数据,需先获取合并单元格的相关信息,并据此推导正确的单元格值。
可通过以下代码获取工作表中的合并单元格配置信息:
const merges = sheet['!merges'] || [];
接着,定义一个名为 getMergedCellValue 的函数,用于根据行列坐标获取合并单元格的实际值:
function getMergedCellValue(sheet, row, col) {
for (const merge of merges) {
const { s, e } = merge; // s: 合并区域的起始位置,e: 合并区域的结束位置
if (row >= s.r && row <= e.r && col >= s.c && col <= e.c) {
return sheet[xlsx.utils.encode_cell(s)]?.v;
}
}
return sheet[xlsx.utils.encode_cell({ r: row, c: col })]?.v;
}
获取表头数据
假设表头数据位于 Excel 的第 4 行,可通过以下代码提取表头信息:
const headerTemplates = [];
const rowIndex = 3; // 第 4 行的索引(从 0 开始)
const range = xlsx.utils.decode_range(sheet['!ref']);
for (let col = range.s.c; col <= range.e.c; col++) {
const cellValue = getMergedCellValue(sheet, rowIndex, col);
if (cellValue) {
const address = xlsx.utils.encode_cell({ r: rowIndex, c: col }) + '';
headerTemplates.push({
address: address,
value: removeTabsAndNewlines(cellValue),
col: col + 1 // Excel 列从 1 开始计数
});
}
}
输出表头模板数据
最后,将提取到的表头数据以 JSON 格式进行输出:
console.log(JSON.stringify(headerTemplates, null, 2));
[Running] node "c:\Users\xiong\WebstormProjects\backendnodejs\src\models\scripts\tempCodeRunnerFile.js"
[
{
"address": "A4",
"value": "序号",
"col": 1
},
{
"address": "B4",
"value": "区县",
"col": 2
},
{
"address": "C4",
"value": "线下收到需求时间(以邮件为准等书面通知为准)",
"col": 3
},
{
"address": "D4",
"value": "订单编号",
"col": 4
},
{
"address": "E4",
"value": "未进系统原因",
"col": 5
},
{
"address": "F4",
"value": "年份",
"col": 6
},
{
"address": "G4",
"value": "运营商",
"col": 7
},将数据转换为结构化 JSON
从第 5 行(即索引为 4 的行)开始遍历数据,将每一行数据转换为对象。对象的键对应表头字段,值对应单元格内容。最终将所有数据存入数组中:
const xlsx = require('xlsx');
const path = require('path');
// 读取 Excel 文件
const filePath = path.join(__dirname, 'YD-TP2025-03-22.xlsx');
const workbook = xlsx.readFile(filePath);
// 获取名为 "建设全流程明细" 的工作表
const sheetName = "建设全流程明细";
const sheet = workbook.Sheets[sheetName];
// 获取工作表的合并单元格信息
const merges = sheet['!merges'] || [];
// 定义一个函数,用于获取合并单元格的值
function getMergedCellValue(sheet, row, col) {
for (const merge of merges) {
const { s, e } = merge;
if (row >= s.r && row <= e.r && col >= s.c && col <= e.c) {
return sheet[xlsx.utils.encode_cell(s)]?.v;
}
}
return sheet[xlsx.utils.encode_cell({ r: row, c: col })]?.v;
}
// 获取表头数据(第 4 行)
const headerRow = [];
const headerRowIndex = 3; // 第 4 行的索引(从 0 开始)
const range = xlsx.utils.decode_range(sheet['!ref']);
// 获取表头
for (let col = range.s.c; col <= range.e.c; col++) {
const cellValue = getMergedCellValue(sheet, headerRowIndex, col);
headerRow.push(cellValue || '');
}
// 将数据转换为列表
const dataList = [];
// 从第5行开始读取数据(索引4)
for (let row = headerRowIndex + 1; row <= range.e.r; row++) {
const rowData = {};
// 遍历每一列
for (let col = range.s.c; col <= range.e.c; col++) {
const cellValue = getMergedCellValue(sheet, row, col);
// 使用表头作为键名
rowData[headerRow[col]] = cellValue || '';
}
dataList.push(rowData);
}
// 输出前5条数据作为示例
console.log('数据总条数:', dataList.length);
console.log('前5条数据示例:');
console.log(JSON.stringify(dataList.slice(5, 25), null, 2));
[Running] node "c:\Users\xiong\WebstormProjects\backendnodejs\src\models\scripts\excel_tolist.js" 数据总条数: 9 前5条数据示例: [ { "序号": 5, "区县": "长沙县", "线下收到需求时间\n(以邮件为准等书面通知为准)": 45523, "订单编号": "新建选址", "未进系统原因": "新建选址完成后进系统", "年份": "2024年", "运营商": "移动", "项目归属": "岳麓山景区", "运营商批次": "普通5G", "重点项目打标": "", "需求站址名称": "长沙岳麓岳麓山东门路口微站H-H5X", "铁塔站址名称": "", "铁塔站址编码": "", "项目编码/存量满足": "", "立项方式(存量满足常规塔类/区域化塔类/非标改造)": "微站", "运营商建设方式(新址新建、共址新建、共址改造)": "新址新建", "铁塔建设方式(新建、改造、存满)": "新建", "产品单元数": 1, "建设类型(地面站,楼面站)": "地面站", "建设方案\n(含所有建设工程量)": "利旧电力路灯杆,新增光电一体箱,新增支臂,外市电", "打标": "2、地面新建", "订单导入时间": "", ............
总结
通过上述步骤,我们成功利用 Node.js 读取了 Excel 文件,并解决了合并单元格数据的处理问题。该方法不仅适用于表头数据的提取,也可应用于其他复杂 Excel 数据的处理场景。
关于 Node.js 读取 Excel 文件并处理合并单元格的介绍到此结束。如需了解更多 Node.js 读取 Excel 的相关内容,建议查阅本站往期文章或继续浏览后续内容。感谢支持!