35
41

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

JavaScriptでつくるExcel→JSON変換アプリ

Last updated at Posted at 2017-12-13

un-T factory! XA Advent Calendar 14日目の記事です。

#はじめに
un-T System! の山中です。フロントエンドエンジニアです。

JavaScriptでMacアプリをつくることができるって知ってましたか?
物は試しと、ExcelをJSONに変換するアプリをつくってみました。
Appleによると、この技術はJXA(JavaScript for Automation)という呼び名らしいです。

#きほん
開発にはMac(OS X Yosemite以降)に標準で入ってる「スクリプトエディタ」を使用します。
script_editor.png
すごくシンプルなエディタです。

  1. スクリプトエディタを立ち上げる
  2. 左上の言語メニューで 「JavaScript」を選択。(選べるのはAppleScriptかJavaScript)
  3. コードを書く
  4. ファイル → 書き出す(ファイルフォーマット:アプリケーション)

これだけでアプリをつくることができます。 簡単。

#つくった
制作したアプリのコードはこちらです。
Excelファイルをドラッグ&ドロップすると、JSONファイルが書き出されます。
(注:実行にはMicrosoft Excelがインストールされている必要があります。)

JavaScript(JXA)

function analyzeExcel(path) {
  var app, worksheets;
  app = Application('Microsoft Excel');
  app.includeStandardAdditions = true;
  app.activate();
  app.open(path);
  worksheets = app.worksheets;

  // ワークシートごとにJSONをつくる
  for (var i = 0; i < worksheets.length; i++) {
    makeJSON(worksheets[i]);
  }

  function makeJSON(ws) {
    var data = {};
    var title = [];
    var first_row = ws.rows[0];
    var worksheet_name = ws.name();

    // 1行目を見出しとして取得
    for (var col_i = 0; ; col_i++) {
       var check = first_row.columns[col_i].value();
       if (!check) {
          break;
       }
       title.push(check);
    }

    // 2行目からデータとして取得
    for (var row_i = 1; ; row_i++) {
       var row = ws.rows[row_i];
       var row_data = {};
       // 1列目でデータの有無を判断
       var id = row.columns[0].value();
       if (!id) {
          break;
       } else {
          data[id] = {};
       }
       // 行ごとにデータをまとめる
       // 同じ見出しがあれば、配列にまとめる
       for (var i = 1; i < title.length; i++) {
          if (row_data[title[i]]) {
             // 配列化
             if (!Array.isArray(row_data[title[i]])) {
                row_data[title[i]] = [row_data[title[i]]];
             }
             // 追加
             if (row.columns[i].value()) {
                row_data[title[i]].push(row.columns[i].value());
             }
          } else {
             row_data[title[i]] = row.columns[i].value();
          }
       }
       data[id] = row_data;
    }

    // 書き出し設定
    var filePath = app.chooseFileName({
       defaultName: worksheet_name + '.json',
       defaultLocation: app.pathTo('desktop')
    });

    // JSONデータを書き出す(文字コードをUTF-8に変換)
    ObjC.import('Cocoa');
    var text = JSON.stringify(data, null, '  ');
    string = $.NSString.stringWithString(text);
    string.writeToFileAtomicallyEncodingError(
      filePath.toString(),
      true,
      $.NSUTF8StringEncoding,
      $()
    );
  }
}

// アプリにファイルをドラッグ&ドロップした時の処理
var SystemEvents = Application("System Events");
var fileTypesToProcess = ["ELSX"];
var extensionsToProcess = ["xlsx"];
var typeIdentifiersToProcess = [];
function openDocuments(droppedItems) {
  for (var item of droppedItems) {
    var alias = SystemEvents.aliases.byName(item.toString());
    var extension = alias.nameExtension();
    var fileType = alias.fileType();
    var typeIdentifier = alias.typeIdentifier();
    if (
       fileTypesToProcess.includes(fileType) 
       || extensionsToProcess.includes(extension)
       || typeIdentifiersToProcess.includes(typeIdentifier)
    ) {
      var path = Path(item.toString().slice(1));
      analyzeExcel(path);
    }
  }
}

// アプリのアイコンをダブルクリックした時に使い方を説明する
function run() {
  var sys = Application("System Events");
  sys.includeStandardAdditions = true;
  sys.displayDialog("Excelファイル(xlsx)をドラッグ&ドロップしてください。JSONファイルに変換します。");
}


以下が変換ルールです。

  • ExcelのワークシートごとにJSONファイルを作成
  • 1行目を見出し、2行目以降を値として扱う
  • 1列目の値をキーに使い、行ごとにデータをまとめる
  • 見出しが同じ場合、配列にする
  • UTF-8に変換する(変換しないと文字化け)

たとえば、このようなExcelファイルをドラッグ&ドロップすると…

table.png

このようなJSONが書き出されます!

JSON
{
  "a": {
    "name": "John",
    "num": [
      11,
      12,
      13
    ]
  },
  "b": {
    "name": "Paul",
    "num": [
      21,
      22
    ]
  },
  "c": {
    "name": "George",
    "num": [
      31
    ]
  },
  "d": {
    "name": "Ringo",
    "num": ""
  }
}

#まとめ
求めている情報を探すのに時間がかかりました。(スクリプトエディタのライブラリは読みにくい!)
ただ、JavaScriptを使うことができるという利点は大きいです。
いろいろな事が出来るみたいなので、何か便利なものをつくりながら知見を貯めていこうと思います。

35
41
0

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
35
41

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?