LoginSignup
97
130

More than 5 years have passed since last update.

JavaScriptでExcel(XLSX)を読み込む

Last updated at Posted at 2017-08-08

概要

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

ちなみにExcelを使わないという選択肢も効率化の中にはあるのですが、それはまた別の機会に取り組みます。
とりあえず今回のテーマはJavaScriptでExcelを読み込むです。

Sheet.js

今回も必要なものは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では動くみたいです。

97
130
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
97
130