JSONをCSVに変換
ネストしたオブジェクトや配列も明示的に処理。サイズ上限もアップロードもありません。
貼り付けたものがブラウザの外に出ることはありません。 connect-src の許可リストにより、これは約束ではなくブラウザによる保証になっています。 自分で確かめる
CSVは四角く、JSONは木です。だからどのコンバーターも、いくつもの判断を下さなければなりません。多くはそれを黙って行います。このページは、判断を下し、それを明示し、変更できるようにしています。
ファイルサイズの上限も1日の回数制限もありません。それを課すサーバーが存在しないからです。
列は「和集合」であり、最初のオブジェクトではない
もっとも影響の大きい判断です。先頭要素のキーだけを読むコンバーターは、あとのレコードにしか現れないフィールドを黙って捨てます。そしてそれに気づくのは、レポートから列がひとつ消えている下流の工程です。
このツールは全行のすべてのパスを、最初に現れた順に集めます。処理は遅くなりますが、正しくなります。JavaScriptでもっとも使われているCSVライブラリであるPapa Parseは、既定では最初のオブジェクトを採用し、そうでない挙動にはcolumnsオプションを明示する必要があります。自分で作るなら知っておく価値のある点です。
行の中の配列:4つの方針と、1つの既定値
ここが本当に判断の分かれるところで、正解はなく、あるのは「妥当な既定値」だけです。
- インデックス列(既定)
- tags.0、tags.1のようになります。情報を失わず、往復もできます。長い配列がひとつあるだけで列数が爆発するのが代償です。
- 1つのセルに結合
- 値をセミコロンでつなぎます。読みやすく、情報は失われ、値に区切り文字が含まれていると危険です。
- 1つのセルにJSONのまま
- 配列をJSONテキストとしてシリアライズします。情報を失わず簡潔ですが、下流で再パースが必要です。
- 行に展開
- 配列の要素ごとに1行を出力し、スカラーの列は繰り返します。pandasのjson_normalizeにおけるrecord_pathです。1対多の関係には正しく、それ以外にはすべて誤りなので、明示的に有効にする方式で、指定したパスにのみ適用されます。
Excelについて、選択の余地がない2点
- UTF-8のバイトオーダーマーク
- ExcelはCSVの中のUTF-8を判別しません。ファイル先頭にBOMがないと、システムのコードページとしてバイト列を読み、アクセント付き文字も絵文字もすべて文字化けします。ここでBOMが既定で有効なのはまさにそのためで、BOMで詰まるパイプライン向けにワンクリックで無効にできます。
- 数式インジェクション
- =、+、-、@ のいずれかで始まるセルは、Excel、Google スプレッドシート、LibreOfficeで数式として実行されます。あなたが生成したCSVの中の =HYPERLINK("http://evil","click") という値は、他人の表計算ソフトで生きたリンクになります。OWASPはこれをCSVインジェクションと呼びます。該当するセルには既定でアポストロフィを前置し、そうしたことをツールが通知します。
nullと空文字列
JSONではこの2つは別の値ですが、Excelはどちらも空白として表示します。そのため多くのコンバーターは両者をひとつに潰してしまい、区別が失われます。ここではnullをクォートなしの空セル、空文字列をクォート付きの空セルにするので、往復しても情報が残ります。空文字列1つあたり2文字の増加で済み、その価値があります。
How to do this in code
コードでの変換と、正しさを左右する引数について。
py Python、pandas
encoding="utf-8-sig"が、Excelの必要とするBOMをpandasで書き出す方法です。素のutf-8では、Excelが読み違えるファイルになります。
import pandas as pd
# Flatten nested objects to dotted columns
df = pd.json_normalize(records)
df.to_csv('out.csv', index=False, encoding='utf-8-sig')
# One row per element of a nested array
df = pd.json_normalize(records, record_path='items', meta=['id']) sh jq
文字列の埋め込みではなく@csvを使ってください。クォートの規則を代わりに処理してくれます。
# Union of keys as the header, then the rows
jq -r '(map(keys) | add | unique) as $c
| $c, (.[] | [.[$c[]]])
| @csv' records.json > out.csv
# @csv quotes and escapes correctly; @text does not js JavaScript
import Papa from 'papaparse';
// Pass the union explicitly. Without it, Papa takes the keys of
// the first object and silently drops the rest.
const columns = [...new Set(records.flatMap(Object.keys))];
const csv = Papa.unparse(records, { columns }); go Go
w := csv.NewWriter(f)
w.Write(columns)
for _, rec := range records {
row := make([]string, len(columns))
for i, c := range columns {
row[i] = fmt.Sprint(rec[c])
}
w.Write(row)
}
w.Flush() よくある質問
- ExcelでCSVの文字が化けるのはなぜですか?
- ファイルはUTF-8ですが、Excelがシステムのコードページとして読んだからです。バイトオーダーマークのオプションは有効のままにしてください。表計算ソフト以外に渡すファイルなら無効にしてください。BOMを最初の列名の一部として扱うパーサーがあるためです。
- いくつかのセルがアポストロフィで始まっているのはなぜですか?
- =、+、-、@ のいずれかで始まっていたからです。表計算ソフトはそれらを数式として実行します。アポストロフィがそれを無効化します。生の値が必要で、ファイルの行き先を信頼できるなら、このオプションをオフにしてください。
- データがオブジェクトの配列でない場合は?
- 単一のオブジェクトは1行になります。スカラーの配列は1列になります。{"data": [...]}のようなラッパーは内側の配列を使い、それが規則ではなく推測であるため、そう判断したことを明示します。
- ヨーロッパ版Excelにはどの区切り文字を使えばよいですか?
- セミコロンです。Excelはシステムのリスト区切り文字から区切り文字を決めており、小数点にカンマを使うロケールではそれがセミコロンになります。ドイツやフランスの環境でカンマ区切りのファイルが1列として開かれるのは、そのためです。