欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Node.js利用js-xlsx处理Excel文件的方法详解

程序员文章站 2022-05-26 09:09:11
简介 本文介绍用 node.js 中的 js-xlsx 库来处理 excel 文件。 js-xlsx 库是目前 github 上 star 数量最多的处理 e...

简介

本文介绍用 node.js 中的 js-xlsx 库来处理 excel 文件。

js-xlsx 库是目前 github 上 star 数量最多的处理 excel 的库,功能强大,但上手难度稍大。文档有些乱,不适合快速上手。

本文对 js-xlsx 库进行一定的总结,并提供几个实用的例子供读者测试,学习,交流。

安装

$ npm install xlsx

一些概念

在使用这个库之前,先介绍库中的一些概念。

  • workbook 对象,指的是整份 excel 文档。我们在使用 js-xlsx 读取 excel 文档之后就会获得 workbook 对象。
  • worksheet 对象,指的是 excel 文档中的表。我们知道一份 excel 文档中可以包含很多张表,而每张表对应的就是 worksheet 对象。
  • cell 对象,指的就是 worksheet 中的单元格,一个单元格就是一个 cell 对象。

它们的关系如下:

// workbook
{
 sheetnames: ['sheet1', 'sheet2'],
 sheets: {
 // worksheet
 'sheet1': {
  // cell
  'a1': { ... },
  // cell
  'a2': { ... },
  ...
 },
 // worksheet
 'sheet2': {
  // cell
  'a1': { ... },
  // cell
  'a2': { ... },
  ...
 }
 }
}

用法

基本用法

  • xlsx.readfile 打开 excel 文件,返回 workbook
  • workbook.sheetnames 获取表名
  • workbook.sheets[xxx] 通过表名获取表格
  • 按自己的需求去处理表格
  • 生成新的 excel 文件

具体用法

读取 excel 文件

import xlsx from 'xlsx';
const workbook = xlsx.readfile('someexcel.xlsx', opts);

获取 excel 文件中的表

// 获取 excel 中所有表名
const sheetnames = workbook.sheetnames; // 返回 ['sheet1', 'sheet2']
// 根据表名获取对应某张表
const worksheet = workbook.sheets[sheetnames[0]];

通过 worksheet[address] 来操作表格,以 ! 开头的 key 是特殊的字段。

// 获取 a1 单元格对象
let a1 = worksheet['a1']; // 返回 { v: 'hello', t: 's', ... }
// 获取 a1 中的值
a1.v // 返回 'hello'

// 获取表的有效范围
worksheet['!ref'] // 返回 'a1:b20'
worksheet['!range'] // 返回 range 对象,{ s: { r: 0, c: 0}, e: { r: 100, c: 2 } }

// 获取合并过的单元格
worksheet['!merges'] // 返回一个包含 range 对象的列表,[ {s: { r: 0, c: 0 }, c: { r: 2, c: 1 } } ]

实战

解析 excel 生成 json

tips 事实上,你可以直接通过 xlsx.utils.sheet_to_json(worksheet) 获得同样的结果

注意 本例子中假设表的第一行为字段名

const headers = {};
const data = [];
const keys = object.keys(worksheet);
keys
 // 过滤以 ! 开头的 key
 .filter(k => k[0] !== '!')
 // 遍历所有单元格
 .foreach(k => {
  // 如 a11 中的 a
  let col = k.substring(0, 1);
  // 如 a11 中的 11
  let row = parseint(k.substring(1));
  // 当前单元格的值
  let value = worksheet[k].v;

  // 保存字段名
  if (row === 1) {
   headers[col] = value;
   return;
  }

  // 解析成 json
  if (!data[row]) {
   data[row] = {};
  }
  data[row][headers[col]] = value;
 });

console.log(data); // [ { '姓名': 'test1', '年龄': 20 }, { '姓名': 'test2', '年龄': 10 } ... ]

合并表格

步骤:

  • 读取多份表格
  • 合并数组

tips: 其实合并表格跟 xlsx 没什么关系,只是处理几个数组而已。

sheet1

id name age
1 test1 30
2 test2 20
3 test3 18

sheet2

id country remark
1 china hello
2 america world
3 unkonw ???
let sheet1 = xlsx.utils.sheet_to_json(sheet1);
let sheet2 = xlsx.utils.sheet_to_json(sheet2);

// 先合并 sheet1 和 sheet2,再对统一处理
const result = sheet1.concat(sheet2).reduce((prev, next) => {
 let index = prev.findindex((elem, i) => elem.id === next.id);

 if (index === -1) {
  return prev.concat(next);
 } else {
  prev[index] = object.assign({}, prev[index], next);
  return prev;
 }
}, []);
console.log(result);

// [ { id: '1',
// name: 'test1',
// age: '30',
// country: 'china',
// remark: 'hello' },
// { id: '2',
// name: 'test2',
// age: '20',
// country: 'america',
// remark: 'world' },
// { id: '3',
// name: 'test3',
// age: '18',
// country: 'unkonw',
// remark: '???' } ]

导出表格

步骤:

  • 构建特定的数据结构,如下。
  • 调用 xlsx.writefile(workbook, filename) 即可。
// workbook
{
 sheetnames: ['mysheet'],
 sheets: {
  'mysheet': {
   '!ref': 'a1:e4', // 必须要有这个范围才能输出,否则导出的 excel 会是一个空表
   a1: { v: 'id' },
   ...
  }
 }
}
var _headers = ['id', 'name', 'age', 'country', 'remark']
var _data = [ { id: '1',
    name: 'test1',
    age: '30',
    country: 'china',
    remark: 'hello' },
    { id: '2',
    name: 'test2',
    age: '20',
    country: 'america',
    remark: 'world' },
    { id: '3',
    name: 'test3',
    age: '18',
    country: 'unkonw',
    remark: '???' } ];

var headers = _headers
    // 为 _headers 添加对应的单元格位置
    // [ { v: 'id', position: 'a1' },
    // { v: 'name', position: 'b1' },
    // { v: 'age', position: 'c1' },
    // { v: 'country', position: 'd1' },
    // { v: 'remark', position: 'e1' } ]
    .map((v, i) => object.assign({}, {v: v, position: string.fromcharcode(65+i) + 1 }))
    // 转换成 worksheet 需要的结构
    // { a1: { v: 'id' },
    // b1: { v: 'name' },
    // c1: { v: 'age' },
    // d1: { v: 'country' },
    // e1: { v: 'remark' } }
    .reduce((prev, next) => object.assign({}, prev, {[next.position]: {v: next.v}}), {});

var data = _data
    // 匹配 headers 的位置,生成对应的单元格数据
    // [ [ { v: '1', position: 'a2' },
    //  { v: 'test1', position: 'b2' },
    //  { v: '30', position: 'c2' },
    //  { v: 'china', position: 'd2' },
    //  { v: 'hello', position: 'e2' } ],
    // [ { v: '2', position: 'a3' },
    //  { v: 'test2', position: 'b3' },
    //  { v: '20', position: 'c3' },
    //  { v: 'america', position: 'd3' },
    //  { v: 'world', position: 'e3' } ],
    // [ { v: '3', position: 'a4' },
    //  { v: 'test3', position: 'b4' },
    //  { v: '18', position: 'c4' },
    //  { v: 'unkonw', position: 'd4' },
    //  { v: '???', position: 'e4' } ] ]
    .map((v, i) => _headers.map((k, j) => object.assign({}, { v: v[k], position: string.fromcharcode(65+j) + (i+2) })))
    // 对刚才的结果进行降维处理(二维数组变成一维数组)
    // [ { v: '1', position: 'a2' },
    // { v: 'test1', position: 'b2' },
    // { v: '30', position: 'c2' },
    // { v: 'china', position: 'd2' },
    // { v: 'hello', position: 'e2' },
    // { v: '2', position: 'a3' },
    // { v: 'test2', position: 'b3' },
    // { v: '20', position: 'c3' },
    // { v: 'america', position: 'd3' },
    // { v: 'world', position: 'e3' },
    // { v: '3', position: 'a4' },
    // { v: 'test3', position: 'b4' },
    // { v: '18', position: 'c4' },
    // { v: 'unkonw', position: 'd4' },
    // { v: '???', position: 'e4' } ]
    .reduce((prev, next) => prev.concat(next))
    // 转换成 worksheet 需要的结构
    // { a2: { v: '1' },
    //  b2: { v: 'test1' },
    //  c2: { v: '30' },
    //  d2: { v: 'china' },
    //  e2: { v: 'hello' },
    //  a3: { v: '2' },
    //  b3: { v: 'test2' },
    //  c3: { v: '20' },
    //  d3: { v: 'america' },
    //  e3: { v: 'world' },
    //  a4: { v: '3' },
    //  b4: { v: 'test3' },
    //  c4: { v: '18' },
    //  d4: { v: 'unkonw' },
    //  e4: { v: '???' } }
    .reduce((prev, next) => object.assign({}, prev, {[next.position]: {v: next.v}}), {});

// 合并 headers 和 data
var output = object.assign({}, headers, data);
// 获取所有单元格的位置
var outputpos = object.keys(output);
// 计算出范围
var ref = outputpos[0] + ':' + outputpos[outputpos.length - 1];

// 构建 workbook 对象
var wb = {
 sheetnames: ['mysheet'],
 sheets: {
  'mysheet': object.assign({}, output, { '!ref': ref })
 }
};

// 导出 excel
xlsx.writefile(wb, 'output.xlsx');

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对的支持。

出处

http://scarletsky.github.io/2016/01/30/nodejs-process-excel/

参考资料

https://github.com/sheetjs/js-xlsx

http://*.com/questions/30859901/parse-xlsx-with-node-and-create-json