Excel 시트의 내용을 javascript에서 json으로 변환하여 pug용 파일로 출력한 메모

동기



홈페이지 작성에 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/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을 출력한다

    좋은 웹페이지 즐겨찾기