使用 xlsx/sheetjs 添加动态列
Add dynamic columns with xlsx/ sheetjs
我有一个包含 ID 和数据的多个标签的数组:
[
{
"id": "tagID1",
"error": { "code": 0, "success": true },
"data": [
[1604395417575, 108, 3],
[1604395421453, 879, 3]
]
},
{
"id": "tagID2",
"error": {"code": 0, "success": true},
"data": [
[1604395417575, 508, 3],
[1604395421453, 179, 3]
]
}
]
我想使用来自 NPM 的 xlsx 包将此数据转换为 Excel 传播sheet。
注:1604395417575为时间戳,608为价值,3为质量。
我想在 Excel sheet 中显示为以下格式
| Timestamp | tagID1 value | tagID1 quality | tagID2 value | tagID2 quality|
| -------- | -------------- | -------- ------| -------------| ------------- |
| 1604395417575| 108 | 3 | 508 | 3 |
| 1604395421453| 879 | 3 | 179 | 3 |
更新Sheet格式
|----------------------------------------------------------
| Timestamp | TagID-1 | TagID-2 |
| | ----------------------------------------
| | value | quality | value | quality |
|----------------------------------------------------------
| 1604395417575| 108 | 3 | 508 | 3 |
| 1604395421453| 879 | 3 | 179 | 3 |
我是 XLSX(又名 SheetJS)的新手 - 我该怎么做?
下面代码中遵循的过程是:
- 通过将每个 object 的
id
和 data
属性排列成一个长列表来转换数据
- 添加一个
order
属性 这是 id
末尾的数字,例如1
对于 tagID1
- 按
Timestamp
然后 order
对新数组进行排序 - 如果您的数据已经按该顺序排序,则可能不需要这样做
- 解析 headers 并创建
tagIDN quality
和 tagIDN value
对
- 通过获取唯一时间戳并为每个时间戳创建 1 行,并使用与标签一样多的列对,将数据转换为宽格式
- 第 4 步和第 5 步正在创建可以传递给 XLSX 方法的数组数组
XLSX.utils.aoa_to_sheet
- 因为那些很长的时间戳会被Excel转换为科学计数法,所以将它们设置为
0
的数字格式
- 创建一个工作簿,使用步骤 6 中的方法插入一个 sheet 并保存
工作代码:
const XLSX = require("xlsx");
// input data
const input_data = [
{
"id": "tagID1",
"error": { "code": 0, "success": true },
"data": [
[1604395417575, 108, 3],
[1604395421453, 879, 3]
]
},
{
"id": "tagID2",
"error": {"code": 0, "success": true},
"data": [
[1604395417575, 508, 3],
[1604395421453, 179, 3]
]
}
];
// data transforms
// 1st transform - get long array of objects
const prep = input_data.map(obj => {
return obj.data.map(arr => {
return {
"TimeStamp": arr[0],
"id": obj.id,
"order": +obj.id.substr(5, obj.id.length - 5),
"quality": arr[1],
"value": arr[2]
}
});
}).flat();
// sort by timestamp asc, order asc
prep.sort((a, b) => a.TimeStamp - b.TimeStamp || a.order - b.order);
// headers
const headers = ["Timestamp"].concat(
[...new Set(prep.map(obj => obj.id))]
.map(id => [`${id} quality`, `${id} value`])
.flat()
);
// organise the data - in wide format
const ws_data = [...new Set(prep.map(obj => obj.TimeStamp))]
.map(ts => {
const objByTimestamp = prep.filter(obj => obj.TimeStamp === ts);
let arr = [ts];
objByTimestamp.forEach(obj => arr = arr.concat([obj.quality, obj.value]));
return arr;
});
// prepend the headers
ws_data.unshift(headers);
// to Excel
// new workbook
const wb = XLSX.utils.book_new();
// create sheet with array-of-arrays to sheet method
const ws = XLSX.utils.aoa_to_sheet(ws_data);
// assign sheet to workbook
XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
// set column A as text
const range = XLSX.utils.decode_range(ws['!ref']);
console.log(range);
for (let i = range.s.r; i <= range.e.r; i++) {
const ref = XLSX.utils.encode_cell({r: i , c: 0});
console.log(ref);
ws[ref].z = "0";
}
// save workbook
XLSX.writeFile(wb, "C:\Users\Robin\Desktop\so.xlsx", {});
Excel 输出:
编辑
要在第一行有双 headers 合并单元格(对于标签 ID)- 请参阅更新:
const XLSX = require("xlsx");
// input data
const input_data = [
{
"id": "tagID1",
"error": { "code": 0, "success": true },
"data": [
[1604395417575, 108, 3],
[1604395421453, 879, 3]
]
},
{
"id": "tagID2",
"error": {"code": 0, "success": true},
"data": [
[1604395417575, 508, 3],
[1604395421453, 179, 3]
]
}
];
// data transforms
// 1st transform - get long array of objects
const prep = input_data.map(obj => {
return obj.data.map(arr => {
return {
"TimeStamp": arr[0],
"id": obj.id,
"order": +obj.id.substr(5, obj.id.length - 5),
"quality": arr[1],
"value": arr[2]
}
});
}).flat();
// sort by timestamp asc, order asc
prep.sort((a, b) => a.TimeStamp - b.TimeStamp || a.order - b.order);
// headers
// const headers = ["Timestamp"].concat(
// [...new Set(prep.map(obj => obj.id))]
// .map(id => [`${id} quality`, `${id} value`])
// .flat()
// );
const ids = [...new Set(prep.map(obj => obj.id))];
const headers1 = [""].concat(ids.map(id => Array(2).fill(id)).flat());
const headers2 = ["Timestamp"].concat(ids.map(id => Array(["quality", "value"])).flat()).flat();
// organise the data - in wide format
const ws_data = [...new Set(prep.map(obj => obj.TimeStamp))]
.map(ts => {
const objByTimestamp = prep.filter(obj => obj.TimeStamp === ts);
let arr = [ts];
objByTimestamp.forEach(obj => arr = arr.concat([obj.quality, obj.value]));
return arr;
});
// prepend the headers
ws_data.unshift(headers2);
ws_data.unshift(headers1);
// to Excel
// new workbook
const wb = XLSX.utils.book_new();
// create sheet with array-of-arrays to sheet method
const ws = XLSX.utils.aoa_to_sheet(ws_data);
// assign sheet to workbook
XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
// set column A as text
const range = XLSX.utils.decode_range(ws['!ref']);
for (let i = range.s.r; i <= range.e.r; i++) {
const ref = XLSX.utils.encode_cell({r: i , c: 0});
ws[ref].z = "0";
}
// assign merges to sheet
// https://whosebug.com/questions/53516403/sheetjs-xlsx-how-to-write-merged-cells
const merges = ids.reduce((acc, curr, idx) => {
acc.push({
s: {r: 0, c: 1 + (2 *idx)},
e: {r: 0, c: 1 + (2 *idx) + 1}
});
return acc;
}, []);
ws["!merges"] = merges;
// save workbook
XLSX.writeFile(wb, "C:\Users\Robin\Desktop\so.xlsx", {});
Excel 输出:
方法是按照这个post。
我有一个包含 ID 和数据的多个标签的数组:
[
{
"id": "tagID1",
"error": { "code": 0, "success": true },
"data": [
[1604395417575, 108, 3],
[1604395421453, 879, 3]
]
},
{
"id": "tagID2",
"error": {"code": 0, "success": true},
"data": [
[1604395417575, 508, 3],
[1604395421453, 179, 3]
]
}
]
我想使用来自 NPM 的 xlsx 包将此数据转换为 Excel 传播sheet。
注:1604395417575为时间戳,608为价值,3为质量。
我想在 Excel sheet 中显示为以下格式
| Timestamp | tagID1 value | tagID1 quality | tagID2 value | tagID2 quality|
| -------- | -------------- | -------- ------| -------------| ------------- |
| 1604395417575| 108 | 3 | 508 | 3 |
| 1604395421453| 879 | 3 | 179 | 3 |
更新Sheet格式
|----------------------------------------------------------
| Timestamp | TagID-1 | TagID-2 |
| | ----------------------------------------
| | value | quality | value | quality |
|----------------------------------------------------------
| 1604395417575| 108 | 3 | 508 | 3 |
| 1604395421453| 879 | 3 | 179 | 3 |
我是 XLSX(又名 SheetJS)的新手 - 我该怎么做?
下面代码中遵循的过程是:
- 通过将每个 object 的
id
和data
属性排列成一个长列表来转换数据 - 添加一个
order
属性 这是id
末尾的数字,例如1
对于tagID1
- 按
Timestamp
然后order
对新数组进行排序 - 如果您的数据已经按该顺序排序,则可能不需要这样做 - 解析 headers 并创建
tagIDN quality
和tagIDN value
对
- 通过获取唯一时间戳并为每个时间戳创建 1 行,并使用与标签一样多的列对,将数据转换为宽格式
- 第 4 步和第 5 步正在创建可以传递给 XLSX 方法的数组数组
XLSX.utils.aoa_to_sheet
- 因为那些很长的时间戳会被Excel转换为科学计数法,所以将它们设置为
0
的数字格式
- 创建一个工作簿,使用步骤 6 中的方法插入一个 sheet 并保存
工作代码:
const XLSX = require("xlsx");
// input data
const input_data = [
{
"id": "tagID1",
"error": { "code": 0, "success": true },
"data": [
[1604395417575, 108, 3],
[1604395421453, 879, 3]
]
},
{
"id": "tagID2",
"error": {"code": 0, "success": true},
"data": [
[1604395417575, 508, 3],
[1604395421453, 179, 3]
]
}
];
// data transforms
// 1st transform - get long array of objects
const prep = input_data.map(obj => {
return obj.data.map(arr => {
return {
"TimeStamp": arr[0],
"id": obj.id,
"order": +obj.id.substr(5, obj.id.length - 5),
"quality": arr[1],
"value": arr[2]
}
});
}).flat();
// sort by timestamp asc, order asc
prep.sort((a, b) => a.TimeStamp - b.TimeStamp || a.order - b.order);
// headers
const headers = ["Timestamp"].concat(
[...new Set(prep.map(obj => obj.id))]
.map(id => [`${id} quality`, `${id} value`])
.flat()
);
// organise the data - in wide format
const ws_data = [...new Set(prep.map(obj => obj.TimeStamp))]
.map(ts => {
const objByTimestamp = prep.filter(obj => obj.TimeStamp === ts);
let arr = [ts];
objByTimestamp.forEach(obj => arr = arr.concat([obj.quality, obj.value]));
return arr;
});
// prepend the headers
ws_data.unshift(headers);
// to Excel
// new workbook
const wb = XLSX.utils.book_new();
// create sheet with array-of-arrays to sheet method
const ws = XLSX.utils.aoa_to_sheet(ws_data);
// assign sheet to workbook
XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
// set column A as text
const range = XLSX.utils.decode_range(ws['!ref']);
console.log(range);
for (let i = range.s.r; i <= range.e.r; i++) {
const ref = XLSX.utils.encode_cell({r: i , c: 0});
console.log(ref);
ws[ref].z = "0";
}
// save workbook
XLSX.writeFile(wb, "C:\Users\Robin\Desktop\so.xlsx", {});
Excel 输出:
编辑
要在第一行有双 headers 合并单元格(对于标签 ID)- 请参阅更新:
const XLSX = require("xlsx");
// input data
const input_data = [
{
"id": "tagID1",
"error": { "code": 0, "success": true },
"data": [
[1604395417575, 108, 3],
[1604395421453, 879, 3]
]
},
{
"id": "tagID2",
"error": {"code": 0, "success": true},
"data": [
[1604395417575, 508, 3],
[1604395421453, 179, 3]
]
}
];
// data transforms
// 1st transform - get long array of objects
const prep = input_data.map(obj => {
return obj.data.map(arr => {
return {
"TimeStamp": arr[0],
"id": obj.id,
"order": +obj.id.substr(5, obj.id.length - 5),
"quality": arr[1],
"value": arr[2]
}
});
}).flat();
// sort by timestamp asc, order asc
prep.sort((a, b) => a.TimeStamp - b.TimeStamp || a.order - b.order);
// headers
// const headers = ["Timestamp"].concat(
// [...new Set(prep.map(obj => obj.id))]
// .map(id => [`${id} quality`, `${id} value`])
// .flat()
// );
const ids = [...new Set(prep.map(obj => obj.id))];
const headers1 = [""].concat(ids.map(id => Array(2).fill(id)).flat());
const headers2 = ["Timestamp"].concat(ids.map(id => Array(["quality", "value"])).flat()).flat();
// organise the data - in wide format
const ws_data = [...new Set(prep.map(obj => obj.TimeStamp))]
.map(ts => {
const objByTimestamp = prep.filter(obj => obj.TimeStamp === ts);
let arr = [ts];
objByTimestamp.forEach(obj => arr = arr.concat([obj.quality, obj.value]));
return arr;
});
// prepend the headers
ws_data.unshift(headers2);
ws_data.unshift(headers1);
// to Excel
// new workbook
const wb = XLSX.utils.book_new();
// create sheet with array-of-arrays to sheet method
const ws = XLSX.utils.aoa_to_sheet(ws_data);
// assign sheet to workbook
XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
// set column A as text
const range = XLSX.utils.decode_range(ws['!ref']);
for (let i = range.s.r; i <= range.e.r; i++) {
const ref = XLSX.utils.encode_cell({r: i , c: 0});
ws[ref].z = "0";
}
// assign merges to sheet
// https://whosebug.com/questions/53516403/sheetjs-xlsx-how-to-write-merged-cells
const merges = ids.reduce((acc, curr, idx) => {
acc.push({
s: {r: 0, c: 1 + (2 *idx)},
e: {r: 0, c: 1 + (2 *idx) + 1}
});
return acc;
}, []);
ws["!merges"] = merges;
// save workbook
XLSX.writeFile(wb, "C:\Users\Robin\Desktop\so.xlsx", {});
Excel 输出:
方法是按照这个post。