kintoneから直接Excelファイルに出力する

目次

はじめに

kintoneでExcelファイルを出力するには、csv形式で書き出した後xlsx形式に変換する必要があります。
今回は、JavaScriptカスタマイズを使ってkintoneからボタン1つで直接Excelファイルに出力する方法を紹介します。

できること

Excel出力用の一覧でボタンを押すと、kintoneアプリ内のデータがExcelファイルに出力されます。

補足

  • 出力データは文字列(1行)、文字列(複数行)フィールドのみに対応しています。
  • 文字列(複数行)フィールドの改行がわかるよう、カスタマイズビューからExcelに出力しています。

事前に準備するもの

kintoneの環境が必要です。
開発者ライセンスの取得方法は こちらのページを参照してください。

手順

  1. kintoneアプリの作成
  2. JavaScriptカスタマイズ

kintoneアプリの作成

はじめから作成

ポータル画面のアプリの「+」ボタンをクリックします。

「はじめから作成」をクリックします。

フォームの設定

フォームは以下の画像を参考にして設定します。

以下のフィールドをフォームに配置してください。

フィールドの種類 フィールド名 フィールドコード
レコード番号 レコード番号 レコード番号
文字列 (1行) タイトル title
文字列 (複数行) 詳細 detail

カスタマイズビューの設定

Excel出力用のカスタマイズビューを作成します。「一覧」タブに移動し「+」ボタンをクリックします。

レコード一覧の表示形式に「カスタマイズ」を選択し、以下の画像を参考にして設定します。

HTMLには以下のコードを入力します。

1
2
3
4
5
<button type="button" id="dl-xlsx">Download XLSX</button>
<h3>アプリ内データ</h3>

<table id="tabrecs" class="table-to-export" data-sheet-name="Sheet1">
</table>

「保存」ボタンをクリックし、最後に「アプリの公開」ボタンをクリックすると、アプリが作成されます。

JavaScriptカスタマイズ

下のサンプルコードをコピーしてJavaScriptファイルoutputXLSX.jsとして保存します。

outputXLSX.js

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/*
 * kintone to Excel sample program
 * Copyright (c) 2018 Cybozu
 *
 * Licensed under the MIT License
 * https://opensource.org/license/mit/
*/
(() => {
  'use strict';
  /* global saveAs */

  const CYB = {};

  // xlsx出力するkintoneのフィールド
  CYB.cols = ['title', 'detail'];

  // エレメントの作成
  const createElement = (parent, element, id, objcss, objattr, html) => {
    const el = document.createElement(element);

    if (id) el.id = id;
    if (objcss) {
      Object.assign(el.style, objcss);
    }
    if (objattr) {
      Object.keys(objattr).forEach(attr => {
        el.setAttribute(attr, objattr[attr]);
      });
    }
    if (html) {
      el.innerHTML = html;
    }
    parent.appendChild(el);
  };

  // string to array buffer
  const s2ab = (s) => {
    const buf = new ArrayBuffer(s.length);
    const view = new Uint8Array(buf);

    for (let i = 0; i !== s.length; i += 1) {
      view[i] = s.charCodeAt(i) & 0xFF;
    }

    return buf;
  };

  // xlsxファイルの作成
  const makeExcelFile = () => {
    const wopts = {
      bookType: 'xlsx',
      bookSST: false,
      type: 'binary'
    };
    const workbook = {SheetNames: [], Sheets: {}};
    const nodelist = document.querySelectorAll('table.table-to-export');
    const node = Array.prototype.slice.call(nodelist, 0);

    node.forEach((currentValue, index) => {
      let n = currentValue.getAttribute('data-sheet-name');

      if (!n) {
        n = 'Sheet' + index;
      }
      workbook.SheetNames.push(n);
      workbook.Sheets[n] = XLSX.utils.table_to_sheet(currentValue, wopts);
    });

    const wbout = XLSX.write(workbook, wopts);
    saveAs(new Blob([s2ab(wbout)], {type: 'application/octet-stream'}), 'test.xlsx');
  };

  // Excel出力ビューを開いたときの処理
  const indexDisplayMakeExcelElement = async () => {
    const tab = document.getElementById('tabrecs');

    document.getElementById('dl-xlsx').addEventListener('click', makeExcelFile);

    try {
      // kintoneのデータを全件取得
      const client = new KintoneRestAPIClient();
      const resrec = await client.record.getAllRecords({app: kintone.app.getId(), fields: CYB.cols});

      if (resrec.length < 1) {
        throw new Error('レコードが登録されていません');
      } else {
        // kintoneのデータをtableに出力する
        resrec.forEach((record, i) => {
          const trname = 'tr' + i;
          createElement(tab, 'tr', trname);
          const trElement = document.getElementById(trname);

          CYB.cols.forEach((col, j) => {
            const tdname = trname + 'td' + j;
            createElement(trElement, 'td', tdname,
              {borderWidth: 'thin', borderStyle: 'solid'},
              null, record[col].value.replace(/\r?\n/g, '<br>'));
          });
        });
      }
    } catch (error) {
      alert(error.message);
    }
  };

  // 一覧画面が開かれたとき
  kintone.events.on(['app.record.index.show'], (ev) => {
    if (document.getElementById('dl-xlsx')) {
      indexDisplayMakeExcelElement();
    }
    return ev;
  });
})();

コード解説

一覧画面を開いたときのイベントapp.record.index.showの発生時に、出力用のデータを作成しています。

106
107
108
109
110
111
112
// 一覧画面が開かれたとき
kintone.events.on(['app.record.index.show'], (ev) => {
  if (document.getElementById('dl-xlsx')) {
    indexDisplayMakeExcelElement();
  }
  return ev;
});

kintone-rest-api-clientのgetAllRecordsメソッドで、kintoneのレコードを全件取得します。
詳細は kintone-rest-api-clientを参照してください。

80
81
82
// kintoneのデータを全件取得
const client = new KintoneRestAPIClient();
const resrec = await client.record.getAllRecords({app: kintone.app.getId(), fields: CYB.cols});

取得したデータからエレメントを作成します。

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// エレメントの作成
const createElement = (parent, element, id, objcss, objattr, html) => {
  const el = document.createElement(element);

  if (id) el.id = id;
  if (objcss) {
    Object.assign(el.style, objcss);
  }
  if (objattr) {
    Object.keys(objattr).forEach(attr => {
      el.setAttribute(attr, objattr[attr]);
    });
  }
  if (html) {
    el.innerHTML = html;
  }
  parent.appendChild(el);
};

エレメントからHTMLのtableを作成します。

87
88
89
90
91
92
93
94
95
96
97
98
99
// kintoneのデータをtableに出力する
resrec.forEach((record, i) => {
  const trname = 'tr' + i;
  createElement(tab, 'tr', trname);
  const trElement = document.getElementById(trname);

  CYB.cols.forEach((col, j) => {
    const tdname = trname + 'td' + j;
    createElement(trElement, 'td', tdname,
      {borderWidth: 'thin', borderStyle: 'solid'},
      null, record[col].value.replace(/\r?\n/g, '<br>'));
  });
});

ボタンをクリックしたタイミングで、ライブラリを使用してtableからxlsxへ書き出します。

48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// xlsxファイルの作成
const makeExcelFile = () => {
  const wopts = {
    bookType: 'xlsx',
    bookSST: false,
    type: 'binary'
  };
  const workbook = {SheetNames: [], Sheets: {}};
  const nodelist = document.querySelectorAll('table.table-to-export');
  const node = Array.prototype.slice.call(nodelist, 0);

  node.forEach((currentValue, index) => {
    let n = currentValue.getAttribute('data-sheet-name');

    if (!n) {
      n = 'Sheet' + index;
    }
    workbook.SheetNames.push(n);
    workbook.Sheets[n] = XLSX.utils.table_to_sheet(currentValue, wopts);
  });

  const wbout = XLSX.write(workbook, wopts);
  saveAs(new Blob([s2ab(wbout)], {type: 'application/octet-stream'}), 'test.xlsx');
};

また、いくつかライブラリも使っているので、それらもkintoneに適用します。
outputXLSX.jsと併せて、PC用のJavaScriptファイルに記述してください。

Cybozu CDNのライブラリ - URLで指定します。

Cybozu CDN外のライブラリ - GitHubからダウンロードしたファイルをアップロードして適用します。

  • sheetjs (External link)
    • dist/xlsx.full.min.js v0.20.1を適用
    • Apache License 2.0
  • FileSaver (External link)
    • FileSaver.min.js v1.3.4を適用
      (FileSaver.jsのv1.3.6以降を利用する場合、ソースからビルドする必要があるため)
    • MIT License

すべてアップロードすると、以下のようになります。
アプリへのJavaScript/CSSファイルのアップロードの方法はヘルプサイトの JavaScriptやCSSでアプリをカスタマイズする (External link) を参照してください。

動作確認

冒頭でお見せしたとおり、Excel出力用に作成した一覧(カスタマイズビュー)に移動し「Download XLSX」ボタンを押すと、kintoneのデータがxlsx形式に出力されます。

おわりに

これまで、csv形式で出力するか、Excel側にVBAを埋め込むという方法はあったものの、直接kintoneからxlsx形式で出力する方法は公開されていませんでした。
Excelファイルが読み込めるサービスとの連携の敷居、より低くなりますね。

デモ環境

デモ環境で実際に動作を確認できます。
https://dev-demo.cybozu.com/k/299/ (External link)

ログイン情報は cybozu developer networkデモ環境で確認してください。

information

このTipsは、2024年1月版kintoneで動作を確認しています。