使用 Node 解析 XLSX 并创建 json
Posted
技术标签:
【中文标题】使用 Node 解析 XLSX 并创建 json【英文标题】:Parse XLSX with Node and create json 【发布时间】:2015-08-31 19:38:23 【问题描述】:好的,所以我发现 node_module
被称为 js-xlsx 的文档记录得很好
问题:如何解析 xlsx 以输出 json?
Excel 工作表如下所示:
最终json应该是这样的:
[
"id": 1,
"Headline": "Team: Sally Pearson",
"Location": "Austrailia",
"BodyText": "...",
"Media: "..."
,
"id": 2,
"Headline": "Team: Rebeca Andrade",
"Location": "Brazil",
"BodyText": "...",
"Media: "..."
]
index.js:
if(typeof require !== 'undefined')
console.log('hey');
XLSX = require('xlsx');
var workbook = XLSX.readFile('./assets/visa.xlsx');
var sheet_name_list = workbook.SheetNames;
sheet_name_list.forEach(function(y) /* iterate through sheets */
var worksheet = workbook.Sheets[y];
for (z in worksheet)
/* all keys that do not begin with "!" correspond to cell addresses */
if(z[0] === '!') continue;
// console.log(y + "!" + z + "=" + JSON.stringify(worksheet[z].v));
);
XLSX.writeFile(workbook, 'out.xlsx');
【问题讨论】:
你想达到什么目的?如果您只想以 json 结构共享 Excel 工作表,或者只是将 Excel 工作表基于云以方便共享,那么有很多产品可以做这样的事情。例如ipushpull.com 花钱。而且我知道这个库会完成手头的简单任务 也有试用版,但如果你想使用比原始库更用户友好的东西,基本上你需要付费。从您的问题来看,您并不清楚您要达到什么目标或问题是什么。您是否想将第一行添加到最终的 json 中? 更新了问题的可读性 您不能将文档另存为 CSV 吗?这将使解析更加简单,文档似乎也不包含任何丰富的格式。 【参考方案1】:我认为这段代码会做你想做的事。它将第一行存储为一组标头,然后将其余行存储在一个数据对象中,您可以将其作为 JSON 写入磁盘。
var XLSX = require('xlsx');
var workbook = XLSX.readFile('test.xlsx');
var sheet_name_list = workbook.SheetNames;
sheet_name_list.forEach(function(y)
var worksheet = workbook.Sheets[y];
var headers = ;
var data = [];
for(z in worksheet)
if(z[0] === '!') continue;
//parse out the column, row, and value
var col = z.substring(0,1);
var row = parseInt(z.substring(1));
var value = worksheet[z].v;
//store header names
if(row == 1)
headers[col] = value;
continue;
if(!data[row]) data[row]=;
data[row][headers[col]] = value;
//drop those first two rows which are empty
data.shift();
data.shift();
console.log(data);
);
打印出来
[ id: 1,
headline: 'team: sally pearson',
location: 'Australia',
'body text': 'majority have…',
media: 'http://www.youtube.com/foo' ,
id: 2,
headline: 'Team: rebecca',
location: 'Brazil',
'body text': 'it is a long established…',
media: 'http://s2.image.foo/' ]
【讨论】:
你就是乔希!我对保存文件进行了一些编辑。享受你的赏金 我想读取一个 xlsx 文件并将该数据转换为 JSON。这有可能吗?还有其他建议吗?? 非常非常好!只发现一件事:当列名以AA
、AB
开头时,代码会丢失宽表的列...因为这些行var col = z.substring(0,1);
和var row = parseInt(z.substring(1));
。将其更改为const column = z.replace(/[0-9]/g, '')
和const row = parseInt(z.replace(/\D/g,''))
,现在它可以完全正常工作了。
很好,但是它跳过了工作表中的空白单元格,这些单元格对我来说应该是 null 或 '',例如:K 列的标题是重量,k1 的值为 72,所以它返回因为重量:'72',k3 值为 65,所以重量:'65',但 k2 单元格留空,所以它没有返回任何东西,我想要重量:''或重量:null,如果我有任何解决方案,它将是给我很大的安慰,请帮我解决这个问题,非常感谢【参考方案2】:
“Josh Marinacci”答案的改进版本,它将超出 Z 列(即 AA1)。
var XLSX = require('xlsx');
var workbook = XLSX.readFile('test.xlsx');
var sheet_name_list = workbook.SheetNames;
sheet_name_list.forEach(function(y)
var worksheet = workbook.Sheets[y];
var headers = ;
var data = [];
for(z in worksheet)
if(z[0] === '!') continue;
//parse out the column, row, and value
var tt = 0;
for (var i = 0; i < z.length; i++)
if (!isNaN(z[i]))
tt = i;
break;
;
var col = z.substring(0,tt);
var row = parseInt(z.substring(tt));
var value = worksheet[z].v;
//store header names
if(row == 1 && value)
headers[col] = value;
continue;
if(!data[row]) data[row]=;
data[row][headers[col]] = value;
//drop those first two rows which are empty
data.shift();
data.shift();
console.log(data);
);
【讨论】:
伙计,我希望两年后你不要再调用变量y
,z
,tt
,更新你的代码是一个巨大的痛苦
这里到底发生了什么?什么是z? tt是什么?
@StormMuller 看到我的回答它有角度解决方案,变量的正常命名
它有效,但如何?查看变量的命名,如果需要更改某些内容,则必须对过程进行逆向工程。下面的答案具有相同的代码,但命名更好。【参考方案3】:
你也可以使用
var XLSX = require('xlsx');
var workbook = XLSX.readFile('Master.xlsx');
var sheet_name_list = workbook.SheetNames;
console.log(XLSX.utils.sheet_to_json(workbook.Sheets[sheet_name_list[0]]))
【讨论】:
它不返回空值,这意味着如果值为空,它不会添加到json中 是的,默认情况下它不处理空白单元格,但通过将可选参数传递给 XLSX.readFile 函数是一种解决方法。 var workbook = XLSX.readFile('Master.xlsx', sheetStubs: true);可选对象中的 sheetStubs 参数允许库列出默认情况下被库的数据处理实用程序忽略的单元格。 请注意它应该是XLSX.utils.sheet_to_json(sheet, defval: "")
而不是XLSX.utils.sheet_to_json(sheet, defVal="")
【参考方案4】:
这里是 Angular 5 方法版本,对于那些在接受的答案中与 y
、z
、tt
苦苦挣扎的人来说,它的语法没有缩小。用法:parseXlsx().subscribe((data)=> ...)
parseXlsx()
let self = this;
return Observable.create(observer =>
this.http.get('./assets/input.xlsx', responseType: 'arraybuffer' ).subscribe((data: ArrayBuffer) =>
const XLSX = require('xlsx');
let file = new Uint8Array(data);
let workbook = XLSX.read(file, type: 'array' );
let sheetNamesList = workbook.SheetNames;
let allLists = ;
sheetNamesList.forEach(function (sheetName)
let worksheet = workbook.Sheets[sheetName];
let currentWorksheetHeaders: object = ;
let data: Array<any> = [];
for (let cellName in worksheet) //cellNames example: !ref,!margins,A1,B1,C1
//skipping serviceCells !margins,!ref
if (cellName[0] === '!')
continue
;
//parse colName, rowNumber, and getting cellValue
let numberPosition = self.getCellNumberPosition(cellName);
let colName = cellName.substring(0, numberPosition);
let rowNumber = parseInt(cellName.substring(numberPosition));
let cellValue = worksheet[cellName].w;// .w is XLSX property of parsed worksheet
//treating '-' cells as empty on Spot Indices worksheet
if (cellValue.trim() == "-")
continue;
//storing header column names
if (rowNumber == 1 && cellValue)
currentWorksheetHeaders[colName] = typeof (cellValue) == "string" ? cellValue.toCamelCase() : cellValue;
continue;
//creating empty object placeholder to store current row
if (!data[rowNumber])
data[rowNumber] =
;
//if header is date - for spot indices headers are dates
data[rowNumber][currentWorksheetHeaders[colName]] = cellValue;
//dropping first two empty rows
data.shift();
data.shift();
allLists[sheetName.toCamelCase()] = data;
);
this.parsed = allLists;
observer.next(allLists);
observer.complete();
)
);
【讨论】:
【参考方案5】:我找到了更好的方法
function genrateJSONEngine()
var XLSX = require('xlsx');
var workbook = XLSX.readFile('test.xlsx');
var sheet_name_list = workbook.SheetNames;
sheet_name_list.forEach(function (y)
var array = workbook.Sheets[y];
var first = array[0].join()
var headers = first.split(',');
var jsonData = [];
for (var i = 1, length = array.length; i < length; i++)
var myRow = array[i].join();
var row = myRow.split(',');
var data = ;
for (var x = 0; x < row.length; x++)
data[headers[x]] = row[x];
jsonData.push(data);
【讨论】:
【参考方案6】:**podria ser algo asi en react y electron**
xslToJson = workbook =>
//var data = [];
var sheet_name_list = workbook.SheetNames[0];
return XLSX.utils.sheet_to_json(workbook.Sheets[sheet_name_list],
raw: false,
dateNF: "DD-MMM-YYYY",
header:1,
defval: ""
);
;
handleFile = (file /*:File*/) =>
/* Boilerplate to set up FileReader */
const reader = new FileReader();
const rABS = !!reader.readAsBinaryString;
reader.onload = e =>
/* Parse data */
const bstr = e.target.result;
const wb = XLSX.read(bstr, type: rABS ? "binary" : "array" );
/* Get first worksheet */
let arr = this.xslToJson(wb);
console.log("arr ", arr)
var dataNueva = []
arr.forEach(data =>
console.log("data renaes ", data)
)
// this.setState( DataEESSsend: dataNueva )
console.log("dataNueva ", dataNueva)
;
if (rABS) reader.readAsBinaryString(file);
else reader.readAsArrayBuffer(file);
;
handleChange = e =>
const files = e.target.files;
if (files && files[0])
this.handleFile(files[0]);
;
【讨论】:
欢迎来到 ***! :D 如果你评论你的代码或在你的正文中添加一些内容来澄清你的答案,这将使你的答案更好、更容易理解。 @AN German 你救了我的命,今天进行产品部署,我用这段代码修复了它,非常感谢【参考方案7】:这是我使用一些 ramdas 助手的解决方案(在打字稿中)。它支持多个工作表,并返回一个以 key 作为工作表名称的对象。
const parseXLSX = (file: File, cb: callback) =>
const reader = new FileReader()
const rABS = !!reader.readAsBinaryString
reader.onload = (e) =>
const bstr = e?.target?.result
const wb = XLSX.read(bstr, type: rABS ? 'binary' : 'array' )
const sheetNames = wb.SheetNames
const sheetsData = sheetNames.reduce((acc, sheetName) =>
const worksheet = wb.Sheets[sheetName]
const headers: Record<string, string> =
const data: Record<string, unknown>[] = []
keys(worksheet).forEach((key) =>
// removes !ref column
if (String(key)?.[0] !== '!')
// supports wide tables ex: AA1
const column = String(key).replace(/[0-9]/g, '')
const row = parseInt(String(key).replace(/\D/g, ''), 10)
const value = worksheet[key].v
if (row === 1)
headers[column] = value
// this solution does not support when header is not first row
if (headers[column] !== undefined)
if (!data[row])
data[row] =
data[row][headers[column]] = value
)
return
...acc,
[sheetName]: drop(1, data.filter(Boolean)),
, )
cb(sheetsData)
if (rABS) reader.readAsBinaryString(file)
else reader.readAsArrayBuffer(file)
【讨论】:
【参考方案8】:只是稍微改进了@parijat 的答案。
var XLSX = require('xlsx');
var workbook = XLSX.readFile('test.xlsx');
var sheet_name_list = workbook.SheetNames;
sheet_name_list.forEach(function(y)
var worksheet = workbook.Sheets[y];
var headers = ;
var data = [];
for(z in worksheet)
if(z[0] === '!') continue;
//parse out the column, row, and value
var tt = 0;
for (var i = 0; i < z.length; i++)
if (!isNaN(z[i]))
tt = i;
break;
;
var col = z.substring(0,tt);
var row = parseInt(z.substring(tt));
var value = worksheet[z].v;
//store header names
if(row == 1 && value)
headers[col] = value;
continue;
if(!data[row-2]) data[row-2]=;
data[row-2][headers[col]] = value;
//Now no need to drop the data element
console.log(data);
);
【讨论】:
以上是关于使用 Node 解析 XLSX 并创建 json的主要内容,如果未能解决你的问题,请参考以下文章
利用 js-xlsx 实现 Excel 文件导入并解析Excel数据成json格式的数据并且获取其中某列数据