Edited at

JavaScriptでExcel(XLSX)を読み込む

More than 1 year has passed since last update.


概要

前回HTMLのTABLEタグをExcel(XLSX)に出力する方法を投稿したんですが、ここ最近業務の効率化でJavaScriptでExcelを読み込むという方法を使えないかと思ったら、すぐに情報が出てきたので、まとめておきます。

ちなみにExcelを使わないという選択肢も効率化の中にはあるのですが、それはまた別の機会に取り組みます。

とりあえず今回のテーマはJavaScriptでExcelを読み込むです。


Sheet.js

http://sheetjs.com/

今回も必要なものはSheetJSです。

フルパッケージのスクリプトを読み込めば必要なものはすべて入っています。

今回もCDNから取得しました。


構成

オブジェクトを作ったわけなんですが、基本的には参考のページに書いてあることを踏襲しているだけです。


実装

この辺りを参考に作ります。


index.html

<!DOCTYPE html>

<html lang="ja">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title></title>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<form action="" method="get">
<input type="file" name="upload_file" id="import-excel" />
<h2>Result</h2>
<div id="result"></div>
</form>

<script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.11.1/xlsx.full.min.js"></script>
<script src="script.js"></script>
</body>
</html>



script.js

(function (window, document) {

window.ExcelJs = {};
ExcelJs.File = function (_file, _workbook) {
var that = this;
var file = _file;
var workbook = _workbook;

return {
getFile: function () {
return file;
},
getWorkbook: function () {
return workbook;
},
toJson: function () {
var result = {};
workbook.SheetNames.forEach(function(sheetName) {
var roa = XLSX.utils.sheet_to_row_object_array(workbook.Sheets[sheetName]);
if(roa.length > 0){
result[sheetName] = roa;
}
});
return result;
},
toCsv: function () {
var result = [];
workbook.SheetNames.forEach(function(sheetName) {
var csv = XLSX.utils.sheet_to_csv(workbook.Sheets[sheetName]);
if(csv.length > 0){
result.push('SHEET: ' + sheetName);
result.push('');
result.push(csv);
}
});
return result.join("\n");
},
toFormulae() {
var result = [];
workbook.SheetNames.forEach(function(sheetName) {
var formulae = XLSX.utils.get_formulae(workbook.Sheets[sheetName]);
if(formulae.length > 0){
result.push('SHEET: ' + sheetName);
result.push('');
result.push(formulae.join("\n"));
}
});
return result.join("\n");
}
};
};

ExcelJs.Reader = function (_file, onload) {
var that = this;

var file = _file;
var reader = new FileReader();

reader.onload = function(e) {
var data = e.target.result;

// データが多いとString.fromCharCode()でMaximum call stack size exceededエラーとなるので、
// 別途関数で処理をする。
//var arr = String.fromCharCode.apply(null, new Uint8Array(data));
var arr = handleCodePoints(new Uint8Array(data));

if (typeof onload == 'function') {
onload(e, new ExcelJs.File(file, XLSX.read(btoa(arr), {type: 'base64'})));
}
};
reader.readAsArrayBuffer(file);
};
})(window, window.document);

// see: https://github.com/mathiasbynens/String.fromCodePoint/issues/1
function handleCodePoints(array) {
var CHUNK_SIZE = 0x8000; // arbitrary number here, not too small, not too big
var index = 0;
var length = array.length;
var result = '';
var slice;
while (index < length) {
slice = array.slice(index, Math.min(index + CHUNK_SIZE, length)); // `Math.min` is not really necessary here I think
result += String.fromCharCode.apply(null, slice);
index += CHUNK_SIZE;
}
return result;
}

function renderResult(name, content) {
var elem = document.getElementById('result');
var html = elem.innerHTML;
html += '<h3>' + name + '</h3>';
html += '<pre>' + content + '</pre>';
elem.innerHTML = html;
}

document.getElementById('import-excel').addEventListener('change', function (evt) {
var files = evt.target.files;
var i, f;
for (i = 0, f = files[i]; i != files.length; ++i) {
var er = new ExcelJs.Reader(f, function (e, xlsx) {
renderResult(xlsx.getFile().name, JSON.stringify(xlsx.toJson(), null, 2));
});
}
}, false);


ファイルのアップロード用のフォームにxlsxファイルをアップロードすると画面に出力されます。

サンプル作りました。

demo


注意点、疑問点

ファイルのロードタイミングは処理のタイミングとずれる(onloadイベントで通知される)ので、すべてを読み込んで処理させたい場合は、そういう処理を書いてあげる必要があります。

あとJSON形式で取得するときに複数のシートにデータが入っているのに、1シート分のデータしかJSONに変換されないことがあるみたいです。

あまり詳しく調べてないんで、何とも言えませんが、これなんか使えそう。

ローカルでも動くみたいだから、ちょっとした業務効率もできそう。(みたいな本が売ってたような気がする)

一応、Chrome、Firefox、Edgeでは動くみたいです。