Excel в JSON с помощью JavaScript
Нужно конвертировать Excel в JSON. Создал форму:
div>
<input type="file" id="uploadFile" name="uploadFile" accept=".xls, .xlsx" />
<a> href="#" uname="@fileObj.FileUniqueName" class="uploadData">Загрузить</a>
</div>
Импортировал зависимость:
<script src="https://cdnjs.cloudflare.com/ajax/libs/xls/0.7.6/xls.min.js"></script>
В интернете нашел следующею подходящею функцию. Вот в таком виде она работает:
var oFileIn;
$(function () {
oFileIn = document.getElementById('uploadFile');
if (oFileIn.addEventListener) {
oFileIn.addEventListener('change', ExcelToJSON, false);
}
});
function ExcelToJSON(oEvent) {
// Get The File From The Input
var oFile = oEvent.target.files[0];
var sFilename = oFile.name;
// Create A File Reader HTML5
var reader = new FileReader();
// Ready The Event For When A File Gets Selected
reader.onload = function (e) {
var data = e.target.result;
var cfb = XLS.CFB.read(data, { type: 'binary' });
var wb = XLS.parse_xlscfb(cfb);
// Loop Over Each Sheet
wb.SheetNames.forEach(function (sheetName) {
// Obtain The Current Row As CSV
var sCSV = XLS.utils.make_csv(wb.Sheets[sheetName]);
var oJS = XLS.utils.sheet_to_row_object_array(wb.Sheets[sheetName]);
$("#my_file_output").html(sCSV);
console.log(oJS)
});
};
// Tell JS To Start Reading The File.. You could delay this if desired
reader.readAsBinaryString(oFile);
}
Мне нужно, чтобы она срабатывала при нажатии на ссылку. Для этого я её немного переделал и получился следующий вариант:
$(".uploadData").click(function () {
var data = ExcelToJSON();
//data.append("uname", $(this).attr('uname')); //Other data
$.ajax({
type: "POST",
//url: "http://10.1.48.68:80/uploadinmeta/api/FileApi/uploadData",
url: "http://localhost:6141/api/FileApi/uploadData",
contentType: "application/json;charset=utf-8",
processData: false,
data: JSON.stringify(data),
success: function (response) {
alert(response);
console.log(response);
},
error: function (result, status, er) {
alert("error: " + result + " status: " + status + " er:" + er);
}
});
});
var ExcelToJSON = function () {
// Get The File From The Input
var oFile = document.getElementById('uploadFile').files[0];
//var oFile = oFileIn.target.files[0];
var sFilename = oFile.name;
// Create A File Reader HTML5
var reader = new FileReader();
var json_objects = []
// Ready The Event For When A File Gets Selected
reader.onload = function (e) {
var data = e.target.result;
var cfb = XLS.CFB.read(data, { type: 'binary' });
var wb = XLS.parse_xlscfb(cfb);
// Loop Over Each Sheet
wb.SheetNames.forEach(function (sheetName) {
// Obtain The Current Row As CSV
var sCSV = XLS.utils.make_csv(wb.Sheets[sheetName]);
var json_object = XLS.utils.sheet_to_row_object_array(wb.Sheets[sheetName]);
json_objects.push(json_object);
$("#my_file_output").html(sCSV);
console.log(json_object)
});
};
return json_objects;
// Tell JS To Start Reading The File.. You could delay this if desired
reader.readAsBinaryString(oFile);
}
Но моя реализация срабатывает не до конца, вот эта часть функции не отрабатывает:
reader.onload = function (e) {
var data = e.target.result;
var cfb = XLS.CFB.read(data, { type: 'binary' });
var wb = XLS.parse_xlscfb(cfb);
// Loop Over Each Sheet
wb.SheetNames.forEach(function (sheetName) {
// Obtain The Current Row As CSV
var sCSV = XLS.utils.make_csv(wb.Sheets[sheetName]);
var json_object = XLS.utils.sheet_to_row_object_array(wb.Sheets[sheetName]);
json_objects.push(json_object);
$("#my_file_output").html(sCSV);
console.log(json_object)
});
};
Где накосячил, как можно исправить?
Проблема в том, что если смотреть через отладчик, то он даже не заходит вот в эту часть функции:
reader.onload = function (e) {
var data = e.target.result;
var cfb = XLS.CFB.read(data, { type: 'binary' });
var wb = XLS.parse_xlscfb(cfb);
// Loop Over Each Sheet
wb.SheetNames.forEach(function (sheetName) {
// Obtain The Current Row As CSV
var sCSV = XLS.utils.make_csv(wb.Sheets[sheetName]);
var json_object = XLS.utils.sheet_to_row_object_array(wb.Sheets[sheetName]);
json_objects.push(json_object);
$("#my_file_output").html(sCSV);
console.log(json_object)
});
};
дойдя да этой части он встает вот на эту строку:
reader.onload = function (e) {
а потом сразу перепрыгивает на строку за этой функцией:
return json_objects;
Содержание объектов reder и oFile перед исполнением:
reader: FileReader
error: null
onabort: null
onerror: null
onload: null
onloadend: null
onloadstart: null
onprogress: null
readyState: 0
result: null
oFile: File
lastModified: 1621684181841
lastModifiedDate: Sat May 22 2021 16:49:41 GMT+0500 (Екатеринбург, стандартное время) {}
name: "Test.xls"
size: 25088
type: "application/vnd.ms-excel"
webkitRelativePath: ""
__proto__: File
Смущает, что у объекта FileReader все либо null либо 0
Объект event функции reader.onload, почему-то как будто слушает мышь

При начальном (рабочем) варианте функции переменная события e имеет другое содержание, содержит в т.ч. srcElement: FileReader {readyState: 2,, которого нет в моем варианте:

Думаю все дело в данной переменной события е (event), которая имеет отличное от первоначального (рабочего) варианта функции.
Ответы (1 шт):
Возникающая ошибка и не выполнение кода обработчика события reader.onload() связано с тем, что его исполнение откладывается на потом, когда файл будет прочитан браузером, но сначала выполнится весь оставшийся код функции ExcelToJSON(). ExcelToJSON() сразу возвращает пустой массив, потому что reader.onload() ещё не сработал.
Для решения данной проблемы необходимо обработчик события вызывающий ExcelToJSON() сделать асинхронным (async), а вызов ExcelToJSON() произвести с оператором await, который укажет, что необходимо дождаться полного исполнения данной функции. Сам обработчик reader.onload() и возврат результата его работы обернуть в Promise, чтобы обозначить, что этот блок должен точно выполниться как единое целое.
В итоге получается следующее решение:
$(".uploadData").click(async function () {
var data = await ExcelToJSON('AccrualsPaymentsSocialRent');
if (data != undefined & data.length > 0){
data = data[0];
}
$.ajax({
type: "POST",
url: "http://localhost:6141/api/FileApi/uploadData",
contentType: "application/json;charset=utf-8",
processData: false,
data: JSON.stringify(data),
success: function (response) {
alert(response);
console.log(response);
},
error: function (result, status, er) {
alert("error: " + result + " status: " + status + " er:" + er);
}
});
});
var ExcelToJSON = function (sheetNameRead) {
// Get The File From The Input
var oFile = document.getElementById('uploadFile').files[0];
//var oFile = oFileIn.target.files[0];
var sFilename = oFile.name;
// Create A File Reader HTML5
var reader = new FileReader();
var json_objects = [];
return new Promise(resolve => {
// Ready The Event For When A File Gets Selected
reader.onload = function (event) {
var data = event.target.result;
var cfb = XLSX.read(data, { type: 'binary' });
// Loop Over Each Sheet
cfb.SheetNames.forEach(function (sheetName) {
if (sheetName == sheetNameRead) {
// Obtain The Current Row As CSV
var sCSV = XLS.utils.make_csv(cfb.Sheets[sheetName]);
var json_object = XLS.utils.sheet_to_json(cfb.Sheets[sheetName]);
json_objects.push(json_object);
}
});
resolve(json_objects);
};
// Tell JS To Start Reading The File.. You could delay this if desired
reader.readAsBinaryString(oFile);
});
}