fujiike.jp

いろいろあるので、いろいろ書いていく。

クライアントサイドでJSONからCSVを生成する【Excel対応版】 2020-12-12

この記事は、 Makuake Advent Calendar 2020 12日目の記事です。

背景

CSVダウンロード機能などを開発する際、以下のような悩みがあった。

  • 生成したCSVファイルの置き場所や管理に悩む
  • そもそも生成するときにtmpディレクトリへの読み書きが必要でなんかキモチワルイ
  • サーバーサイドはJSON APIを想定して組んでおり、利用するフレームワークがCSV出力と親和性が低い

それでなくとも、システムの言語が変わるたびにCSV出力のやり方を学び直すのもなんだかツラいので、
WEB前提ならクライアントサイドで生成できる方が汎用性が高いと考えた。

利用技術

今回は Papa Parse を利用した方法を紹介する。
便利すぎて今後CSV出力は全部これでやりたいってなったのでぜひ紹介したいやつ。

今回のサンプルでは Vue.js のコンポーネントで利用することを想定し、
CSVとして利用可能なblobを生成する処理と、それをブラウザ上でダウンロードできるようにする処理を紹介する。

サンプルコード

事前に yarn add papaparse または npm install papaparse などで、パッケージの取り込みを行う。 package.json で管理しているなら、 "papaparse": "^5.2.0", などを追記してもよい。

// ファイルの配置は @/modules/csv.js を想定した
import Papa from 'papaparse'

const getDownloadableBlob = (json) => {
  const csv = Papa.unparse(json)
  // utf8のCSVでも、bomという情報を持たせるとエクセルが形式を解釈してくれて文字化けせずに開ける
  const bom = new Uint8Array([0xEF, 0xBB, 0xBF])
  const blob = new Blob([bom, csv], { type: 'text/csv' })
  return blob
}

export default {
  getDownloadableBlob
}

<template>
  <!--
    aタグのdownload属性を使ってCSVダウンロードを実現するため、
    DOMはaタグである必要がある。
  -->
  <a
    @click="handleClickDownloadCsv"
    id="csvDownloader"
  >
    CSVダウンロード
  </a>
</template>
<script>
import csv from '@/modules/csv'

export default {
  methods: {
    handleClickDownloadCsv () {
      // keyにCSVのヘッダ文字列を、
      // 配列の各valueに各列のデータを入力する。
      const json = [
        {
          ID: 1,
          苗字: '田中',
          名前: '太郎',
          メールアドレス: 'sample1@email.com'
        },
        {
          ID: 2,
          苗字: '田中',
          名前: '次郎',
          メールアドレス: 'sample2@email.com'
        }
      ]
      const blob = csv.getDownloadableBlob(json)
      const filename = `sample.csv`
      if (window.navigator.msSaveBlob) { // IE/Edge判定
        // IE/Edgeの場合は
        window.navigator.msSaveBlob(blob, filename)
      } else { // Chrome, Firefox, Safari判定
        const dom = document.getElementById('csvDownloader')
        // ダウンロード時のファイル名指定には aタグの download 属性を使う
        dom.download = filename
        // blobデータからダウンロード用のURLを生成する
        dom.href = window.URL.createObjectURL(blob)
        dom.click()
      }
    }
  }
}
</script>

ポイントだと個人的に思うところはコードのコメントに記載しているので、別で詳細な解説はありません。ご了承のほど何卒。

Blob と createObjectURL はそれ自体慣れていない人はちょっと勉強するといろいろわかりやすくなると思うので、
blob & createObjectURL について
などを読むといい感じだと思います。

所感

とにかく便利なのでちょっとしたCSV生成なら絶対これをお勧めしたいぐらい好き。

APIから取ってきた情報を整形して流し込むだけでCSVにできたりするので、
商品一覧画面などでCSV生成を作成するときも、共通のデータソースを参照しやすいなどメリットが多いと感じる。

CSV生成で設計に悩んだらぜひ検討してみてください。

おわり。