LoginSignup
39
37

More than 5 years have passed since last update.

ブラウザ上でCSVファイルをパースする

Last updated at Posted at 2016-06-24

背景

CSVファイルのアップロード機能を考えます。
一番シンプルな方法は、formタグにinput type="file"タグを入れて、指定したファイルをPOSTします。

例えば、HTMLタグ/フォームタグ/ファイルの送信欄を作る - TAG index Webサイト です。

問題

CSVファイルのバリデーションにサーバーへの送信が必須です。
POST前にチェックできれば、ユーザが意図しないCSVファイルを指定した場合に、迅速なフィードバックを返せます。
便利なユーザーインタフェースが作れます。

また、CSVファイルの仕様は

  • エスケープ
  • 区切り文字
  • 改行文字
  • ファイルのエンコーディング

を考慮する必要があります。面倒です。
自分では、パーサーを書きたくありません。

解決策

npmパッケージとして公開されているCSVパーサーを利用します。
今回は、csv-parserを使って、ブラウザ上でCSVファイルをパースします。

csv-parserは

id,first_name,last_name,email,gender,ip_address
1,Paul,Hill,phill0@yahoo.com,Male,213.190.9.236

のようなCSVを

{
  "id": "1",
  "first_name": "Paul",
  "last_name": "Hill",
  "email": "phill0@yahoo.com",
  "gender": "Male",
  "ip_address": "213.190.9.236"
}

JavaScriptオブジェクトに変換します。

browserifyを使うと、npmパッケージをブラウザで動くJavaScriptに変換できます。

実装

ユーザが指定したファイルを取得

input type="file"は指定ファイルが変わるとchangeイベントを早出します。
inputfiles属性からFileオブジェクトが取得できます。

document.querySelector('input')
  .addEventListener('change', (e) => {
    const file = e.target.files[0] // ファイルが取れます。
  })

イベントオブジェクトのtarget属性には、input要素(イベントが発生した要素)が入っています。

ファイルの中身を読み込む

File APIのreadAsText関数を使って読み込みます。

readAsText関数は引数にFileオブジェクトを指定できます。

const reader = new FileReader
reader.readAsText(file)

このとき第二引数でエンコードを指定できます。
WindowsのExeclで作ったCSVファイルを読み込むときは'shift-jis'を指定すると、文字化けを回避できます。

ファイルの読み込みは非同期で行われます。読み込みが終わるとonloadハンドラーが呼ばれます。
読み込んだ結果はinputresultプロパティから取得できます。

const reader = new FileReader
reader.onload = (e) => {
  const content = e.target.result // ファイルの中身が取れます。
}

CSVのパース

csv-parserを使います。
csv-parserはStream APIを実装しています。

データ入力

入力データをwrite関数で渡します。

文字列かBufferオブジェクトが指定できます。
readAsTextの読み取り結果は文字列です。そのまま指定できます。

const csv = require('csv-parser')
const stream = csv()

stream.write(e.target.result)

readAsArrayBufferを利用してArrayBufferオブジェクトを指定した場合はBuffuerに変換する必要があります。

const csv = require('csv-parser')
const stream = csv()

stream.write(new Buffer(e.target.result))

データ取得

変換結果はdataイベントハンドラーで取得します。

const csv = require('csv-parser')
const stream = csv()

stream.on('data',(data) => {
  const object = data // objectにパースされた値が取得できます。
})

ソースコード

index.js

index.js
const csv = require('csv-parser')
const stream = csv()

stream.on('data', function(data) {
  console.log(data)
})

document.querySelector('input')
  .addEventListener('change', (e) => {
    const reader = new FileReader
    reader.onload = (e) => {
      stream.write(e.target.result)
    }

    if (e.target.files[0]) {
      const file = e.target.files[0]
      reader.readAsText(file)
    }
  })

index.html

index.html
<input type="file">
<script src="bundle.js" charset="utf-8"></script>

実行

npm init -y
npm i -D browserify csv-parser
node_modules/browserify/bin/cmd.js index.js bundle.js

index.htmlを開きます。

動作イメージ

スクリーンショット 2016-06-24 14.05.04.png

その他

テスト用のCSVファイルはMockaroo - Random Data Generator | CSV / JSON / SQL / Excelで作りました。

参考

39
37
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
39
37