import get from 'lodash-es/get.js'
import each from 'lodash-es/each.js'
import map from 'lodash-es/map.js'
import values from 'lodash-es/values.js'
import arrHas from './arrHas.mjs'
import isbol from './isbol.mjs'
import cstr from './cstr.mjs'
import getCsvStrFromData from './getCsvStrFromData.mjs'
import getXLSX from './_getXLSX.mjs'
function toStr(v) {
if (isbol(v)) {
return v ? 'true' : 'false'
}
return cstr(v)
}
function to_array(workbook, valueToString) {
let result = []
workbook.SheetNames.forEach(function (sheetname) {
//sheet_to_json
//資料轉json後, 各列會欄位名稱為依照英文A開始編號
//不能用raw:false轉出字串數據, 長整數會被以科學記號顯示而失去精度
//需使用defval='', 否則各列中若有無效值會跳過造成錯位
let arr = getXLSX().utils.sheet_to_json(workbook.Sheets[sheetname], { header: 'A', defval: '', blankrows: true })
//提取數據
arr = map(arr, (v) => {
return values(v)
})
//valueToString
if (valueToString) {
arr = map(arr, (v) => {
return map(v, (vv) => {
return toStr(vv)
})
})
}
//push
result.push({
sheetname,
data: arr
})
})
return result
}
function to_ltdt(workbook, valueToString) {
let result = []
workbook.SheetNames.forEach(function (sheetname) {
//sheet_to_json
let j = getXLSX().utils.sheet_to_json(workbook.Sheets[sheetname])
//valueToString
if (valueToString) {
j = map(j, (v) => {
each(v, (vv, kk) => {
v[kk] = toStr(vv)
})
return v
})
}
//push
result.push({
sheetname,
data: j
})
})
return result
}
function to_csv(workbook, valueToString) {
//to_array
let shs = to_array(workbook, valueToString)
//bom
let bom = false
//convert
each(shs, (sh, ksh) => {
//save
shs[ksh].data = getCsvStrFromData(sh.data, bom)
})
return shs
}
/**
* 讀取Excel檔,前後端都可用,前端由input file的檔案取得Uint8Array,後端由fs.readFileSync讀取Buffer
* 若數據格式fmt為csv格式,數據分欄符號為逗號,分行符號為[\r\n],內容開頭無BOM,方便使用者解析
*
* Unit Test: {@link https://github.com/yuda-lyu/wsemi/blob/master/test/getDataFromExcelFileU8Arr.test.mjs Github}
* @memberOf wsemi
* @param {Uint8Array} u8a 輸入file資料,格式需為Uint8Array
* @param {Object} [opt={}] 輸入設定物件,預設為{}
* @param {String} [opt.fmt='ltdt'] 輸入數據格式,可有'ltdt','csv','array',預設為'ltdt'
* @param {Boolean} [opt.valueToString=true] 輸入數據是否強制轉字串布林值,預設為true
* @returns {Array} 回傳數據陣列
* @example
*
* // test in browser
* domShowInputAndGetFilesU8Arrs(kind)
* .then(function(d) {
* let file = d[0] //get first file
* let u8a = file.u8a
* let dltdt = getDataFromExcelFileU8Arr(u8a, { fmt: 'ltdt' })
* console.log(dltdt[0].sheetname, dltdt[0].data)
* // => ...
* })
*
* // test in nodejs
* let u8a = fs.readFileSync('temp.xlsx')
* let dltdt = getDataFromExcelFileU8Arr(u8a, { fmt: 'ltdt' })
* console.log(dltdt[0].sheetname, dltdt[0].data)
* // => ...
*
*/
function getDataFromExcelFileU8Arr(u8a, opt) {
//fmt
let fmt = get(opt, 'fmt', 'ltdt')
//check
if (!arrHas(['ltdt', 'csv', 'array'], fmt)) {
return {
error: `opt.fmt is not one of 'ltdt', 'csv', 'array'`
}
}
//valueToString
let valueToString = get(opt, 'valueToString', true)
//check
if (!isbol(valueToString)) {
return {
error: 'opt.valueToString is not a boolean'
}
}
//workbook
let workbook
try {
workbook = getXLSX().read(u8a, { type: 'buffer' }) //Uint8Array
}
catch (err) {
console.log('error: ', err)
return {
error: 'can not read data from u8a'
}
}
//convert
let r = null
try {
if (fmt === 'ltdt') {
r = to_ltdt(workbook, valueToString)
}
else if (fmt === 'array') {
r = to_array(workbook, valueToString)
}
else if (fmt === 'csv') {
r = to_csv(workbook, valueToString)
}
}
catch (err) {
console.log('error: ', err)
return {
error: 'can not convert data'
}
}
return r
}
export default getDataFromExcelFileU8Arr