前書き
CSVのエクスポートは、WEBアプリでは結構利用する機能だと思います。
できる限り、フロント側で完結したい内容ではありますので、JavaScriptで実装してみました。
実装
利用するのは以下二つのライブラリです。
# JsonをCSV文字列に変換してくれるライブラリ
$ npm install papaparse
$ yarn add papaparse
# 文字コード変換をしてくれるライブラリ
$ npm install encoding-japanese
$ yarn add encoding-japanese
Papaparseは、他にもできることが多く、ドキュメントが素晴らしいのでぜひご覧ください。
JSONをCSV形式に変換する処理
Papaparseにオブジェクト配列を渡すことで、簡単にCSV文字列(区切り文字列)に変換してくれます。
import Papa from 'papaparse';
import encoding from 'encoding-japanese';
...
// configの初期値
const config = {
delimiter: ',', // 区切り文字
header: true, // キーをヘッダーとして扱う
newline: '\r\n', // 改行
};
// 区切り文字へ変換
const delimiterString = Papa.unparse(json, config);
// blobUrlへの変換
const strArray = encoding.stringToCode(delimiterString);
const convertedArray = encoding.convert(strArray,'SJIS', 'UNICODE');
const UintArray = new Uint8Array(convertedArray);
const blobUrl = new Blob([UintArray], {type: 'text/csv'});
ソースとしては以上です。
のちにダウンロードを行うため、blobへ変換しています。
その変換過程でencoding(encoding-japanese)のconvertで第2引数の文字コードに変換しています。
ダウンロード処理
ダウンロードでは、擬似的にaタグを利用して、blobを叩いてダウンロードさせるようにします。
const blob = blobUrl;
const aTag = document.createElement('a');
aTag.download = fileName;
// 各ブラウザに合わせ、CSVをダウンロード
if (window.navigator.msSaveBlob) {
// for IE
window.navigator.msSaveBlob(blob, aTag.download);
} else if (window.URL && window.URL.createObjectURL) {
// for Firefox
aTag.href = window.URL.createObjectURL(blob);
document.body.appendChild(aTag);
aTag.click();
document.body.removeChild(aTag);
} else if (window.webkitURL && window.webkitURL.createObject) {
// for Chrome
aTag.href = (window.URL || window.webkitURL).createObjectURL(blob);
aTag.click();
} else {
// for Safari
window.open(
`data:type/csv;base64,${window.Base64.encode(this.state.content)}`,
'_blank'
);
}
ダウンロードの処理には、ほとんどPapaparseもencoding-japaneseも利用しません。
各ブラウザで保存方法が違うので、制御式を書いています。
(aタグ使わずにもっといい書き方あるのかな。。。)
まとめ
まとめとして、一連のソースを記述します。
const config = {
delimiter: ',', // 区切り文字
header: true, // キーをヘッダーとして扱う
newline: '\r\n', // 改行
};
// 区切り文字へ変換
const delimiterString = Papa.unparse(json, config);
// blobUrlへの変換
const strArray = encoding.stringToCode(delimiterString);
const convertedArray = encoding.convert(strArray,'SJIS', 'UNICODE');
const UintArray = new Uint8Array(convertedArray);
const blobUrl = new Blob([UintArray], {type: 'text/csv'});
const blob = blobUrl;
const aTag = document.createElement('a');
aTag.download = fileName;
// 各ブラウザに合わせ、CSVをダウンロード
if (window.navigator.msSaveBlob) {
// for IE
window.navigator.msSaveBlob(blob, aTag.download);
} else if (window.URL && window.URL.createObjectURL) {
// for Firefox
aTag.href = window.URL.createObjectURL(blob);
document.body.appendChild(aTag);
aTag.click();
document.body.removeChild(aTag);
} else if (window.webkitURL && window.webkitURL.createObject) {
// for Chrome
aTag.href = (window.URL || window.webkitURL).createObjectURL(blob);
aTag.click();
} else {
// for Safari
window.open(
`data:type/csv;base64,${window.Base64.encode(this.state.content)}`,
'_blank'
);
}
後書き
フロント側でも簡単にCSVエクスポートが実装できました。
Papaparseを使えば、インポート処理も実装できるので、なかなか重宝します。