Drip 'n' Snip

ドリップン・スニップ

あなたの生活役立つWEB情報イッパイお届け
csvjs

CSVファイルの加工を自動化したい?JavaScriptでやりましょう。


こんにちは!
今回はちょっとエンジニア向けの記事になります。
JavaScriptのお話なので、JSとCSVはよく使う!という方、是非読んでいってください。

CSVの編集が面倒!

CEサイトへの商品の登録や、その他のデータのやり取りで頻繁に使われるCSVですが、ちょっとフォーマットがズレているだけでサービスは受け付けてくれません。
例えば、商品の一覧CSVがあったとして、それをECの販売サイトへ登録したいとします。
その時、CEサイト側では
[ID,商品名,販売価格,在庫数]
というフォーマットで登録しなければならないとしましょう。この時IDの欄は空欄にする必要がある、とします。
しかし、手元に送られてくる商品情報のフォーマットが
[商品名,メーカー名,販売価格,在庫数]
というCSVであった場合、通常はExcelか何かを開いて、
[空欄,商品名,販売価格,在庫数]
というフォーマットの票に1つ1つ貼り付けていく、という作業が発生します。
もちろん、1列は丸っとコピー出来るので、1つのCSVに対して列の数と同じ回数コピペすれば良いという話ではあるのですが、毎回フォーマットが決まっているのに手動で変換するのも馬鹿馬鹿しいですよね。
Excelのマクロを使っても良いのですが、複数枚のシートに跨った編集は若干面倒ですし、マクロを社内の皆で共有するのは結構難しかったりします。
そこで、JavaScriptを使って変換用のwebページを作ってしまえば良いのでは?と思って、ちょっとやってみました。

JavaScriptでCSVを扱うには?

JavaScriptでCSVを扱うためには、5つのステップを経る必要があります。

1.ブラウザにCSVを読み込ませる
2.CSVをJavaScriptで扱える形式(配列)に変換する
3.配列を操作する
4.配列をCSVに戻す
5.ダウンロードする

1.ブラウザにCSVを読み込ませる

ブラウザにCSVを読み込ませるには、input要素のtype="file"を利用します。

input type="file" id="files" name="files[]" multiple

このタグを書くと、それだけで
index_html

こんなボタンが表示されます。

そして、この要素に対して

document.getElementById('files').addEventListener('change', handleFileSelect, false);

このようにイベントリスナをセットします。
そして、このhandeFileSelectの内容を書いていきます。

function handleFileSelect(evt) {
     var file = evt.target.files[0];
     var reader = new FileReader();
     // Closure to capture the file information.

     reader.onload = (function (e) {

         var n = CSV.parse(Encoding.convert(e.target.result, 'UNICODE', 'AUTO'));
         var csv = fillCsv(n);
         SaveToFile('product.csv', csv);

     });

     reader.readAsBinaryString(file);
}

さて、ここで2つ便利なライブラリを利用しています。
1つは
CSV.js
https://github.com/knrz/CSV.js
もう一つは圧縮電子どうのこうの様のencoding.jsです。

http://polygon-planet-log.blogspot.jp/2012/04/javascript.html

var file = evt.target.files[0];

の部分で、ファイルを読み取っています。
multipleを指定しているのでファイルが複数選択される可能性があるのですが、今回はその1つ目のファイルだけを扱います。
つまり複数選択しても反映されません。複数選択を反映させたい場合には各自で改良してください。

そして、FileReader()をインスタンス化し、reader.onloadに、ファイルの読み込みが終わった時に実行したい関数として、読み込んだCSVをユニコードにエンコード→CSVをパースして配列に変換する
という内容を指定しています。

var n = CSV.parse(Encoding.convert(e.target.result, 'UNICODE', 'AUTO'));
var csv = fillCsv(n);
SaveToFile('product.csv', csv);

そして、evt.target.files[0]によって取得されたファイルを、readerのreadAsBinaryString関数を使ってreaderオブジェクトに読み込ませます。
読み込みが終わると同時に、その読み込まれたファイルを使って上記のencodingと配列変換が行われ、その配列がfillCsvという関数に渡されます。

fillCsvは、普通に配列を操作するための関数です。

function fillCsv(_csv) {
     var csv = _csv;
     for (var i = 1; i < csv.length; i++) {
         csv[i][1] = 1;
         csv[i][8] = 0;
         csv[i][11] = 1;
         csv[i][3] = csv[i][3] + ',' + csv[i][23];
         csv[i][3] = csv[i][3] + ',' + csv[i][24];
         csv[i][3] = csv[i][3] + ',' + csv[i][25];
         csv[i].splice(23, 8);
     }
     csv[0].splice(23, 8);
     var csvFile = csvSimple.toCSV(csv);
     return csvFile;
}

内容は例ですが、こんな風に普通の配列としてcsvの内容を操作出来てしまいます!
最後に

var csvFile = csvSimple.toCSV(csv);

の部分で、配列をcsvファイルに直しています。

ここでは
Azisava様の
http://azisava.sakura.ne.jp/js/lib/#csv
このライブラリを使わせて頂きました。
csvSimple.toCSV(2次配列)
とするだけでcsv形式のオブジェクトが生成され、すこぶる便利です。

さて最後に、返ってきたCSVファイルをダウンロードする処理をします。

function SaveToFile(FileName, Stream) {

     if (window.navigator.msSaveBlob) {
         window.navigator.msSaveBlob(new Blob([Stream], {type: "text/csv"}), FileName);
     } else {
         var a = document.createElement("a");
         a.href = URL.createObjectURL(new Blob([Stream], {type: "text/csv"}));
         //a.target   = '_blank';
         a.download = FileName;
         document.body.appendChild(a);//FireFox 
         a.click();
         document.body.removeChild(a);//FireFox 
     }
}

SaveToFileという関数を作っています。
ファイル名とさっきのCSVオブジェクトを渡せばOKです。
最後に、aという名前のhtml要素を作り、それに生成したCSVファイルを渡し、さらにそれをクリックした事にしてファイルをダウンロードさせています。
FireFoxだけちょっと別の挙動が必要なのでその処理もしています。
さて、長くなりましたが全体像を最後に掲載しておきます。
もちろんそれぞれのライブラリは予め読み込んでおく必要があります。

まとめ

さて、ちょっと長く、そして難しくなってしまいましたが、これでJavaScriptでのCSVの操作はバッチリです。
このスクリプトを利用したHTMLを適当な場所にアップしておけば共有も簡単ですし、アップデートする場合にはそのスクリプトを書き換えるだけで済みます。

3種類のライブラリをダウンロードして予め読み込み、

CSV.js
https://github.com/knrz/CSV.js
encoding.js
http://polygon-planet-log.blogspot.jp/2012/04/javascript.html
csvSimple.js
http://azisava.sakura.ne.jp/js/lib/#csv

HTMLに

input type="file" id="files" name="files[]" multiple

を書いて(もちろん<>で全体を囲んでくださいね。)、後は配列をいじっている場所を書き換えればそのまま使うことも出来るはずです。

function handleFileSelect(evt) {

    console.log(evt);
    var file = evt.target.files[0];
    var reader = new FileReader();
    // Closure to capture the file information.
    reader.onload = (function (e) {
        console.log(Encoding.detect(e.target.result));
        var n = CSV.parse(Encoding.convert(e.target.result, 'UNICODE', 'AUTO'));
        console.log(n);
        var csv = fillCsv(n);
        SaveToFile('product.csv', csv);
    });

    reader.readAsBinaryString(file);
}

function fillCsv(_csv) {

    var csv = _csv;

    for (var i = 0; i < csv.length; i++) {
        csv[i][1] = 1;
        csv[i][8] = 0;
        var n = '';
        csv[i][3] = csv[i][3] + ',' + csv[i][23];
        csv[i][3] = csv[i][3] + ',' + csv[i][24];
        csv[i][3] = csv[i][3] + ',' + csv[i][25];
        csv[i].splice(23, 8);
    }

    var csvFile = csvSimple.toCSV(csv);

    return csvFile;

}

function SaveToFile(FileName, Stream) {

     if (window.navigator.msSaveBlob) {
         window.navigator.msSaveBlob(new Blob([Stream], {type: "text/csv"}), FileName);
     } else {
         var a = document.createElement("a");
         a.href = URL.createObjectURL(new Blob([Stream], {type: "text/csv"}));
         //a.target   = '_blank';
         a.download = FileName;
         documen
t.body.appendChild(a);//  FireFox specification
         a.click();
         document.body.removeChild(a);//  FireFox specification
     }
}

document.getElementById('files').addEventListener('change', handleFileSelect, false);

NEXT
iPhoneの画面が割れて反応しなくなった時に、パスコードロックを解除する方法

  関連記事

artboard
【2017年1月】今個人でECサイトを作るなら?【徹底比較】

さて、主・副問わず、個人事業をされている皆さまにおかれましては、内容によっては個 ...

artboard
jQuery Lightboxでページの読み込みを早くしよう!

Wrodpressを使った画像系SEO対策記事2連続ですが、ご容赦くださいませ。 ...

artboard-2
画像素材やベクター素材、どうやって管理してますか?タグ付けしてすぐ検索出来るLingoが便利過ぎてヤバい

こんばんは、僕です。 皆さま、画像素材やsvg素材はどのように管理されていますで ...

sagi
通販詐欺にあった記録と、通販詐欺の見分け方

こんにちは。 恥ずかしながら最近ネット上の通販サイトで詐欺にあってしまいました。 ...

artboard
あのTinypngが自動でかかる!Compress JPEG & PNG imagesが便利すぎ

こんにちは、楽をするためにはどんな努力でも惜しまないタイプの僕ですが、努力が報わ ...

-WEB開発, ノウハウ