使用 Node.js 读取 Excel 文件并处理合并单元格
在现代的数据处理任务中,Excel 文件是一种非常常见的数据存储格式。无论是数据分析、报表生成,还是数据迁移,Excel 文件都扮演着重要的角色。然而,处理 Excel 文件时,尤其是包含合并单元格的文件,可能会遇到一些挑战。本文将介绍如何使用 Node.js 读取 Excel 文件,并处理其中的合并单元格。

准备工作
首先,我们需要安装一些必要的 Node.js 库。我们将使用 xlsx
库来读取和解析 Excel 文件,使用 lodash
库来处理字符串。你可以通过以下命令安装这些库:
bash
npm install xlsx lodash
读取 Excel 文件
我们首先需要读取 Excel 文件。假设我们的文件名为 YD-TP2025-03-22.xlsx
,并且它位于当前项目的根目录下。我们可以使用 xlsx.readFile
方法来读取文件:
javascript
const xlsx = require('xlsx');
const path = require('path');
const filePath = path.join(__dirname, 'YD-TP2025-03-22.xlsx');
const workbook = xlsx.readFile(filePath);
获取工作表
接下来,我们需要获取 Excel 文件中的特定工作表。假设我们的工作表名为 建设全流程明细
,我们可以通过以下代码获取该工作表:
javascript
const sheetName = "建设全流程明细";
const sheet = workbook.Sheets[sheetName];
处理合并单元格
在处理 Excel 文件时,合并单元格是一个常见的挑战。合并单元格的值通常只存储在合并区域的左上角单元格中,其他单元格的值为空。为了正确处理合并单元格,我们需要获取合并单元格的信息,并根据这些信息来获取正确的值。
我们可以通过以下代码获取工作表的合并单元格信息:
javascript
const merges = sheet['!merges'] || [];
然后,我们定义一个函数 getMergedCellValue
,用于获取合并单元格的值:
javascript
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;
}
获取表头数据
假设我们的表头数据位于第 4 行,我们可以通过以下代码获取表头数据:
javascript
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 格式:
javascript
console.log(JSON.stringify(headerTemplates, null, 2));
bash
[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)开始读取数据,并将每一行数据转换为一个对象,其中键为表头字段,值为单元格内容。最后,将所有数据存储在一个数组中
javascript
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));
javascript
[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 数据。希望这篇文章能帮助你在处理 Excel 文件时更加得心应手。
如果你有任何问题或建议,欢迎在评论区留言!