動機
ホームページ作成にpugを使うようになったが、表を作成するためのjsonを手打ちするのが面倒になってきた。
Excelで作成した表をコマンド一発で取り込めるようにする。
動作環境
- windows10
- Excel 2016 MSO(16.0.9001.2080) 32bit
- vagrant1.9.7
- virtualbox5.1.26
- ubuntu-16.04
- Docker version 17.09.0-ce, build afdb6d4
- docker-compose version 1.17.1, build 6d101fb
フォルダ構成
- bin
- excel-to-data.sh
- docker
- excel
- app.js
- Dockerfile
- docker-compose.yml
- data
- chart.js
- htdocs
- pug
- rulebook.pug
- includes
- common
- chart.pug
docker設定
docker/excel/Dockerfile
FROM node:9.5.0
# コンテナ上の作業ディレクトリ作成
WORKDIR /app
# 後で確認出来るようにpackage.jsonを作成
RUN npm init -y
# エクセルを扱う
RUN npm i -D exceljs
docker/excel/app.js
const fs = require('fs');
const excel = require('exceljs');
(async _ =>{
// コンテナ上のパスを記述
const src = `/app/data/chart.xlsx`;
const dest = `/app/dest/chart.pug`;
// エクセルの内容を取得
const sheets = await getSheets(src);
// 書き出すファイルの内容
let content = ``;
// シート名を変数名、変数の値をレコードとして、pugファイルの内容を作成
sheets.forEach(sheet=>{
content += `- ${sheet.name}=${JSON.stringify(sheet.records)}\n`;
});
// ファイルに書き出し
fs.writeFile(dest, content, (err)=>console.log(err));
console.log(`Excel: ${src} to Pug: ${dest} `);
})();
/**
* エクセルファイルを読み込み、シートごとのデータの配列を返す
* @param {*} filepath
* @returns シートごとのデータの配列
*/
async function getSheets(filepath){
const dataArr = [];
const workbook = await readWorkbookAsync(filepath);
workbook.eachSheet(function(worksheet, sheetId){
const data = getSheetData(worksheet);
dataArr.push(data);
});
return dataArr;
}
/**
* シートのデータを取得
* @param {*} sheet
* @returns {name:"シート名", records: [1行目をプロパティ名としたオブジェクトの配列]}
*/
function getSheetData(sheet){
let columIndex=1;
let rowIndex=1;
const headerRow =[];
// 1行目をヘッダとする
while(sheet.getCell(1, columIndex).value !== null){
headerRow.push(sheet.getCell(1, columIndex++).value);
}
const columnCount = headerRow.length;
const dataArr = [];
// 二行目からのデータを取り込み
rowIndex++;
while(sheet.getCell(rowIndex, 1).value !== null){
const data ={};
// ヘッダをプロパティ名として値を設定
for(let col = 0; col < columnCount; col++){
data[headerRow[col]] =sheet.getCell(rowIndex, col + 1).value;
}
dataArr.push(data);
rowIndex++;
}
return {name: sheet.name, records: dataArr};
}
/**
* エクセルファイルを非同期で読み込む
* @param {*} filePath
*/
function readWorkbookAsync(filePath){
return new Promise((resolve, reject) => {
const workbook = new excel.Workbook();
workbook.xlsx.readFile(filePath).then(()=>{
resolve(workbook);
});
});
}
docker-compose.yml
version: '3'
services:
# エクセル取込
excel:
build: ./excel
volumes:
- ./excel/app.js:/app/app.js
- ../data:/app/data
# pugの変数定義ファイルに書き出し
- ../htdocs/pug/includes/common:/app/dest
実行
bin/excel-to-data.sh
#!/bin/bash
# このシェルスクリプトのディレクトリの絶対パスを取得。
bin_dir=$(cd $(dirname $0) && pwd)
cd $bin_dir/../docker && docker-compose run excel /bin/bash -c "node app.js"
エクセルファイル
- data/chart.xlsxを読み込む
- シート名を変数名とする
- 1行目をヘッダとして、オブジェクトのプロパティとする。
出力結果
htdocs/pug/includes/common/chart.pug
- classList=[{"name":"ビッグ","image":"big.png","description":"体が大きいことを表すクラス。恵まれた体格を活かしたアビリティを習得できる。チビと同時に選ぶことはできない。"},{"name":"チビ","image":"tibi.png","description":"体が小さいことを表すクラス。 小器用な立ち回りを活かしたアビリティを習得できる。 ビッグと同時に選ぶことはできない。"},{"name":"オトナ","image":"otona.png","description":"オトナの立ち位置であることを表すクラス。 経験に裏打ちされたアビリティを習得できる。 25歳以上でなければ取得できない。"},{"name":"ニューエイジ","image":"new.png","description":"10年前の災害により、変異を起こしたことを表すクラス。 超能力のアビリティを習得できる。 15歳以下でなければ取得できない。"},{"name":"キズモノ","image":"kizu.png","description":"消えない傷を受けてしまったことを表すクラス。 その不利を補い生きていくためのアビリティを習得できる。 このクラスを選択した場合、部位ダメージを1受けている状態でスタートする。 この、部位ダメージの入っている「身体部位」を<キズ>と呼ぶ。 <キズ>はいかなる手段でも回復しない。"},{"name":"センシ","image":"sensi.png","description":"戦闘が得意なことを表すクラス。 戦闘に必要なアビリティを習得できる。"},{"name":"シノビ","image":"sukauto.png","description":"偵察・調査が得意なことを表すクラス。 探索を有利にするアビリティを習得できる。"},{"name":"ハンター","image":"hunter.png","description":"狩りが得意なことを表すクラス。 飛び道具や罠を用いたアビリティを習得できる。"},{"name":"ハカセ","image":"hakase.png","description":"物知りであることを表すクラス。 知識を活かしたアビリティを習得できる。"},{"name":"ショクニン","image":"syokunin.png","description":"手先が器用であることを表すクラス。 モノづくりに関するアビリティを習得できる。"},{"name":"ホープ","image":"kibou.png","description":"皆の希望である表すクラス。 希望を持つことで運命を変えるアビリティを習得できる。"},{"name":"ママ","image":"mama.png","description":"おかんな立ち位置を表すクラス。 周囲に活力を与えるアビリティを習得できる。"}]
pugで使用する例
htdocs/rulebook.pug
extends includes/common/_layout
block title
include includes/common/variables
include includes/rulebook/variables
title= title
block headjs
include includes/common/chart
block body
body.nohero
header
include includes/common/header
main#main
section.content
.container
h1 終末旅行TRPG 基本ルールブック
include includes/rulebook/first
h2 キャラクター
p あなたの分身となる旅人の作り方
h2 クラス
.listB
.container
each obj in classList
article
a(href="#")
.image(style="background-image: url('../assets/images/" + obj.image + "');")
.text
h2= obj.name
p= obj.description
include includes/common/footer
参考
[Excel] Excel で JSON データを読み込む
Node.jsでエクセルファイルを読み込む
【JavaScript】Excelで読み込んだデータを文字化けさせずにCSVで書き出す
Node.jsでmerged cellしたり色塗ったりしたExcelを出力する