un-T factory! XA Advent Calendar 14日目の記事です。
#はじめに
un-T System! の山中です。フロントエンドエンジニアです。
JavaScriptでMacアプリをつくることができるって知ってましたか?
物は試しと、ExcelをJSONに変換するアプリをつくってみました。
Appleによると、この技術はJXA(JavaScript for Automation)という呼び名らしいです。
#きほん
開発にはMac(OS X Yosemite以降)に標準で入ってる「スクリプトエディタ」を使用します。
すごくシンプルなエディタです。
- スクリプトエディタを立ち上げる
- 左上の言語メニューで 「JavaScript」を選択。(選べるのはAppleScriptかJavaScript)
- コードを書く
- ファイル → 書き出す(ファイルフォーマット:アプリケーション)
これだけでアプリをつくることができます。 簡単。
#つくった
制作したアプリのコードはこちらです。
Excelファイルをドラッグ&ドロップすると、JSONファイルが書き出されます。
(注:実行にはMicrosoft Excelがインストールされている必要があります。)
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ファイルをドラッグ&ドロップすると…
このようなJSONが書き出されます!
{
"a": {
"name": "John",
"num": [
11,
12,
13
]
},
"b": {
"name": "Paul",
"num": [
21,
22
]
},
"c": {
"name": "George",
"num": [
31
]
},
"d": {
"name": "Ringo",
"num": ""
}
}
#まとめ
求めている情報を探すのに時間がかかりました。(スクリプトエディタのライブラリは読みにくい!)
ただ、JavaScriptを使うことができるという利点は大きいです。
いろいろな事が出来るみたいなので、何か便利なものをつくりながら知見を貯めていこうと思います。