xlsx|xlsx 大刀小用,Excel 表格解析
xlsx 又名 SheetJS 是一个强大的 JS 库,用于各种 Excel 操作这里只记录一下解析 Excel 的方法
Excel 【xlsx|xlsx 大刀小用,Excel 表格解析】假设有如下表格:
文章图片
解析成原始数据
/**
* 获取原始数据
* @param {File} file
* @param {Array} schemas
* schemas = [
*{
*name: '用户信息',
*schema: [
*{
*title: 'ID',
*key: 'id'
*},
*{
*title: '姓名',
*key: 'username'
*}
*]
*}
* ]
*/
export function getRawExcelSheets (file, schemas = []) {
return new Promise(resolve => {
const reader = new FileReader()reader.onload = (e) => {
const fileData = https://www.it610.com/article/new Uint8Array(e.target.result)
const workbook = XLSX.read(fileData, { type:'array' })
const result = []// validate sheet names
const validSheetNamesError = validateSheetNames(workbook, schemas)
if (validSheetNamesError) {
return resolve([validSheetNamesError])
}workbook.SheetNames.forEach((sheetName, sheetIndex) => {
// get sheet
const worksheet = workbook.Sheets[sheetName]// convert to json data
// api ref: https://github.com/SheetJS/sheetjs#json
let rows = XLSX.utils.sheet_to_json(worksheet, {
header: 1,
defval: '',
blankrows: false
})rows = trimSheetData(rows)result.push(rows)
})// validate sheet titles
const validSheetTitlesError = validateSheetTitles(result, schemas)
if (validSheetTitlesError) {
return resolve([validSheetTitlesError])
}resolve([null, result])
}reader.readAsArrayBuffer(file)
})
}
结果如下:
文章图片
可以看到,直接变成了二维数组的结构
可是这样操作起来并不是非常的明了,比如
result[0]
代表工作表1,这里也就是 用户信息
这个工作表,而 result[0][0]
则是这个工作表的第一行也就是标题,这数组下表操作写起来太不明了了,如果直接是表格打印倒也没啥解析成键值对的形式 好吧,根据上面的方法,再加利用一下,变成:
/**
* 获取 Excel 数据(变成键值对的形式)
* @param {File} file
* @param {Array} sheets
*/
export function getExcelSheets (file, sheets) {
return new Promise(async resolve => {
let [error, result] = await getRawExcelSheets(file, sheets)if (error) {
return resolve([error])
}result = result.map((rows, sheetIndex) => {
rows.shift()return rows.map(row => {
const item = {}// convert each row to Object
sheets[sheetIndex].columns.forEach(({ key }, colIndex) => {
// key => value
item[key] = row[colIndex]
})return item
})
})resolve([null, result])
})
}
结果如下:
文章图片
完整代码
import XLSX from 'xlsx'/**
* 验证工作表名称
* @param {Object}} workbook
* @param {Array} schemas
*/
function validateSheetNames (workbook, schemas) {
// get sheets names and titles
const sheetNames = schemas.map(({ name }) => name)// validate sheet names
if (JSON.stringify(sheetNames) !== JSON.stringify(workbook.SheetNames)) {
return new Error('Sheet Names Mismatch!')
}return null
}/**
* 验证工作表的标题
* @param {Array} result
* @param {Array} schemas
*/
function validateSheetTitles (result, schemas) {
const sheetTitles = []
const workbookSheetTitles = []schemas.forEach(({ schema }, sheetIndex) => {
sheetTitles[sheetIndex] = schema.map(({ title }) => title)
})result.forEach((rows, sheetIndex) => {
const titles = []for (let i = 0;
i < schemas[sheetIndex].schema.length;
i++) {
titles.push(rows[0][i])
}workbookSheetTitles.push(titles)
})if (JSON.stringify(workbookSheetTitles) !== JSON.stringify(sheetTitles)) {
return new Error('Sheet Header Titles Mismatch!')
}return null
}/**
* 清除表格空行、字段前后空白符
* @param rows
* @param colLength 每行总列数
* @returns {*}
*/
function trimSheetData (rows) {
return rows.filter(row => row.length > 0 && row.filter(option => option !== '').length > 0)
.map(row => row.map(content => {
if (Object.prototype.toString.call(content) === '[object String]') {
return content.trim()
}return content
}))
}/**
* 获取原始数据
* @param {File} file
* @param {Array} schemas
* schemas = [
*{
*name: '用户信息',
*schema: [
*{
*title: 'ID',
*key: 'id'
*},
*{
*title: '姓名',
*key: 'username'
*}
*]
*}
* ]
*/
export function getRawExcelSheets (file, schemas = []) {
return new Promise(resolve => {
const reader = new FileReader()reader.onload = (e) => {
const fileData = https://www.it610.com/article/new Uint8Array(e.target.result)
const workbook = XLSX.read(fileData, { type:'array' })
const result = []// validate sheet names
const validSheetNamesError = validateSheetNames(workbook, schemas)
if (validSheetNamesError) {
return resolve([validSheetNamesError])
}workbook.SheetNames.forEach((sheetName, sheetIndex) => {
// get sheet
const worksheet = workbook.Sheets[sheetName]// convert to json data
// api ref: https://github.com/SheetJS/sheetjs#json
let rows = XLSX.utils.sheet_to_json(worksheet, {
header: 1,
defval: '',
blankrows: false
})rows = trimSheetData(rows)result.push(rows)
})// validate sheet titles
const validSheetTitlesError = validateSheetTitles(result, schemas)
if (validSheetTitlesError) {
return resolve([validSheetTitlesError])
}resolve([null, result])
}reader.readAsArrayBuffer(file)
})
}/**
* 获取 Excel 数据(变成键值对的形式)
* @param {File} file
* @param {Array} schemas
*/
export function getExcelSheets (file, schemas = []) {
return new Promise(async resolve => {
let [error, result] = await getRawExcelSheets(file, schemas)if (error) {
return resolve([error])
}result = result.map((rows, sheetIndex) => {
rows.shift()return rows.map(row => {
const item = {}// convert each row to Object
schemas[sheetIndex].schema.forEach(({ key }, colIndex) => {
// key => value
item[key] = row[colIndex]
})return item
})
})resolve([null, result])
})
}
调用如下:
const schemas = [
{
name: '用户信息',
schema: [
{
title: 'ID',
key: 'id'
},
{
title: '性别',
key: 'gender'
},
{
title: '姓名',
key: 'username'
},
{
title: '年龄',
key: 'age'
}
],
},
{
name: '城市信息',
schema: [
{
title: 'ID',
key: 'id'
},
{
title: '城市名称',
key: 'cityName'
},
{
title: '城市首字母',
key: 'cityInitial'
}
]
}
]const [err, data] = await getRawExcelSheets(file, schemas)if (err) return alert(err)console.log(JSON.stringify(data, null, 4))
总结 主要是使用了一个 schemas 参数去描述这个 Excel 文件的结构,用于表格验证,也用于键值对的输出
demo 源码网址:https://github.com/RoamIn/Doraemon/tree/master/Excel—— 2019/12/12 By Vinci, Mostly Sunny.
推荐阅读
- javascript|vue使用js-xlsx导出excel,可修改格子样式,例如背景颜色、字体大小、列宽等
- vue|vue js-xlsx导入导出excel文件Demo
- 纯前端实现文件导出
- 自制文档格式转换器,支持 .txt/.xlsx/.csv格式转换...
- 前端使用xlsx.js导出excel
- python操作xlsx格式文件并读取
- 一款从小用到大的爽身粉,夏日神器
- Excel无法打开文件xxx.xlsx,因为文件格式或文件扩展名无效。请确定文件未损坏,并且文件扩展名与文件的格式匹配
- vue-使用js-xlsx实现前端上传Excel表格(一)
- 推荐2个免费在线预览word,xlsx,pdf地址