excel-sheet-to-json
Version:
A TypeScript/JavaScript library that converts Excel files to JSON with custom header mapping. Works in both Node.js and browser environments.
178 lines (172 loc) • 6.91 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
var XLSX = require('xlsx');
function _arrayLikeToArray(r, a) {
(null == a || a > r.length) && (a = r.length);
for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
return n;
}
function _createForOfIteratorHelperLoose(r, e) {
var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
if (t) return (t = t.call(r)).next.bind(t);
if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
t && (r = t);
var o = 0;
return function () {
return o >= r.length ? {
done: !0
} : {
done: !1,
value: r[o++]
};
};
}
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _unsupportedIterableToArray(r, a) {
if (r) {
if ("string" == typeof r) return _arrayLikeToArray(r, a);
var t = {}.toString.call(r).slice(8, -1);
return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
}
}
function parse(fileBuffer,
// Buffer | ArrayBuffer (타입 추정)
options) {
// 1. Buffer 읽기 및 워크북 생성
var workbook = XLSX.read(fileBuffer, {
type: 'buffer'
});
var sheetName = workbook.SheetNames[0];
var worksheet = workbook.Sheets[sheetName];
// 2. 빈 행 생략 문제 해결: range 옵션 사용
var sheetRef = worksheet['!ref'];
if (!sheetRef) {
return {
originHeaderNames: [],
fields: [],
header: {},
body: []
}; // 💡 header 초기값 변경
}
var arrayData = XLSX.utils.sheet_to_json(worksheet, {
header: 1,
range: sheetRef,
raw: true
});
// 3. 인덱스 계산 (1-based -> 0-based)
var headerRowIndex = options.headerStartRowNumber - 1;
var bodyRowIndex = options.bodyStartRowNumber - 1;
// 4. 원본 헤더 추출
var rawHeaders = arrayData[headerRowIndex] || [];
var originHeaderNames = rawHeaders.map(function (name) {
return name ? String(name).trim() : '';
}).filter(function (name) {
return name !== '';
});
// 💡 5. fields 배열 및 header 객체 생성 (수정된 로직)
var fields = []; // 매핑 성공한 DB 키 목록 (순서 보존용)
var header = {}; // { DB 키: 원본 헤더 이름 }
originHeaderNames.forEach(function (originName) {
var dbKey = options.headerNameToKey[originName];
// 매핑 테이블에 존재하는 헤더만 처리
if (dbKey) {
fields.push(dbKey);
header[dbKey] = originName; // 💡 DB 키를 Key로, 원본 헤더 이름을 Value로 저장
}
});
// 6. 바디 데이터 (JSON 배열) 변환
var body = [];
for (var i = bodyRowIndex; i < arrayData.length; i++) {
var row = arrayData[i];
var jsonObject = {};
var isEmptyRow = true;
// 7. 각 열을 반복하며 JSON 객체 생성
// 💡 arrayData의 모든 열을 반복하는 것이 아니라, fields 배열의 순서대로 반복해야 합니다.
// 문제: 현재 fields 배열의 순서와 row[j]의 인덱스가 일치한다고 가정한 로직은
// 매핑되지 않은 헤더가 중간에 있을 경우 깨질 수 있습니다.
// 💡 해결책: 매핑 성공한 DB 키(fields) 순서대로 데이터를 찾아 할당합니다.
// 이 문제를 해결하기 위해, arrayData[headerRowIndex]에서 DB 키에 해당하는
// 원본 헤더의 인덱스를 찾아야 합니다.
var isRowDataValid = true;
var _loop = function _loop() {
var dbKey = _step.value;
// 현재 DB 키에 매핑된 원본 헤더 이름
var originName = header[dbKey];
// 원본 헤더 이름이 arrayData[headerRowIndex]에서 몇 번째 인덱스(열)에 있는지 찾습니다.
// Array.prototype.indexOf를 사용하여 찾습니다.
var colIndex = rawHeaders.findIndex(function (name) {
return String(name).trim() === originName;
});
if (colIndex !== -1) {
var cellValue = row[colIndex] || '';
if (cellValue !== null && cellValue !== undefined && String(cellValue).trim() !== '') {
isEmptyRow = false;
}
jsonObject[dbKey] = cellValue;
} else {
// 이 필드는 헤더 행에 존재했지만, 어떤 이유로 찾을 수 없다면 오류로 간주할 수 있습니다.
// 여기서는 매핑을 건너뛰고 다음 필드로 넘어갑니다.
isRowDataValid = false;
}
};
for (var _iterator = _createForOfIteratorHelperLoose(fields), _step; !(_step = _iterator()).done;) {
_loop();
}
// 8. 모든 값이 빈 문자열이거나 null인 행은 건너뜁니다.
// 💡 fields 배열을 기반으로 루프를 돌았으므로, row.length 대신 fields.length로 제어됩니다.
if (!isEmptyRow && isRowDataValid) {
body.push(jsonObject);
}
}
return {
originHeaderNames: originHeaderNames,
fields: fields,
header: header,
body: body
};
}
/**
* 브라우저 환경에서의 File 객체를 ArrayBuffer로 변환합니다.
* @param file - 브라우저 환경에서의 File 객체
* @returns ArrayBuffer로 변환된 파일 데이터
*/
function fileToArrayBufferInClient(file) {
// 파일이 유효한지 확인
if (!file || !(file instanceof File)) {
return Promise.reject(new Error('Input must be a valid File object.'));
}
return new Promise(function (resolve, reject) {
var reader = new FileReader();
// 1. 성공적으로 읽었을 때 처리
reader.onload = function (event) {
var _event$target;
// event.target.result는 readAsArrayBuffer 호출 시 ArrayBuffer 타입입니다.
var arrayBuffer = (_event$target = event.target) == null ? void 0 : _event$target.result;
if (arrayBuffer instanceof ArrayBuffer) {
resolve(arrayBuffer);
} else {
reject(new Error('File reading completed, but result is not ArrayBuffer.'));
}
};
// 2. 파일 읽기 실패 시 처리
reader.onerror = function (error) {
reject(error);
};
// 3. 파일 읽기 시작 (ArrayBuffer 형태로)
reader.readAsArrayBuffer(file);
});
}
function arrayBufferToBufferInClient(arrayBuffer) {
return Buffer.from(arrayBuffer);
}
var ExcelSheetToJson = {
parse: parse,
fileToArrayBufferInClient: fileToArrayBufferInClient,
arrayBufferToBufferInClient: arrayBufferToBufferInClient
};
exports.arrayBufferToBufferInClient = arrayBufferToBufferInClient;
exports.default = ExcelSheetToJson;
exports.fileToArrayBufferInClient = fileToArrayBufferInClient;
exports.parse = parse;
//# sourceMappingURL=excel-sheet-to-json.cjs.development.js.map