JSONからCSVへの変換ツール
JSON配列をCSV形式に変換
JSONからCSVへの変換とは?
JSONからCSVへの変換は、JSON形式の構造化データをコンマ区切り値(表形式)に変換する処理です。スプレッドシート・データベース・分析ツールはCSVをネイティブに扱えます。JSONはネストされたオブジェクトと配列として固定スキーマなしにデータを保存します。CSVはヘッダー行でフィールド名を定義し、行と列としてデータを保存します。この変換によってAPIデータをスプレッドシートやデータベースに届けることができます。
CSV(Comma-Separated Values)はRFC 4180で定義されています。各行が1レコードを表し、行内のフィールドは区切り文字(最も一般的にはカンマ)で区切られます。区切り文字・ダブルクォート・改行を含むフィールドはダブルクォートで囲み、内部のクォートはダブルクォートを重ねてエスケープします。このエスケープ処理が、JSONからCSVへのコンバーターを手書きする際にバグが最も発生しやすい箇所です。
入力が一貫したキーを持つフラットなオブジェクトの配列であれば、変換は単純です。各オブジェクトが1行になり、各ユニークなキーが列ヘッダーになります。ネストされたオブジェクトや配列はフラット化が必要であり、オブジェクト間でキーが不一致の場合は欠損フィールドの扱い方(通常はセルを空にする)が必要です。信頼性の高いコンバーターはこれらのエッジケースをすべて自動的に処理します。
なぜJSONをCSVに変換するのか?
APIはJSONを返しますが、スプレッドシート・SQLデータベース・BIツールは表形式データを必要とします。JSONをCSVに変換することで、カスタムのインポートスクリプトを書くことなくシステム間でデータを移動できます。
JSONからCSVへの変換ユースケース
CSV区切り文字リファレンス
区切り文字は各行のフィールドを区切る文字です。カンマが最も一般的ですが、特定の用途では他の区切り文字が標準です。誤った区切り文字を選ぶと、ファイルを開いたときにフィールドが結合されたり分割されたりします。
| 区切り文字 | 文字 | 拡張子 | 使用場面 |
|---|---|---|---|
| Comma | , | .csv | Default for most spreadsheets and databases |
| Semicolon | ; | .csv | Standard in locales where comma is a decimal separator (DE, FR, BR) |
| Tab | \t | .tsv | Avoids escaping when field values contain commas or semicolons |
| Pipe | | | .csv | Used in fixed-width legacy systems and some ETL pipelines |
CSVにおけるネストされたJSONの扱い
CSVはフラットな形式であり、ネストされたオブジェクトや配列をネイティブに表現する方法がありません。JSONにネスト構造が含まれる場合、コンバーターはそれを列にフラット化する必要があります。いくつかの戦略があり、CSVの使用方法によって適切な選択が異なります。
コード例
JSONからCSVへのプログラム変換には、ヘッダーの抽出・フィールドのクォート・区切り文字のエスケープ処理が必要です。ほとんどの言語にはCSV書き込みの組み込みまたは標準ライブラリサポートがあります。
const data = [
{ name: "Alice", age: 30, city: "Berlin" },
{ name: "Bob", age: 25, city: "Tokyo" },
]
// Extract headers from the first object
const headers = Object.keys(data[0])
const csv = [
headers.join(","),
...data.map(row => headers.map(h => {
const val = String(row[h] ?? "")
// Quote fields that contain commas, quotes, or newlines
return val.includes(",") || val.includes('"') || val.includes("\n")
? '"' + val.replace(/"/g, '""') + '"'
: val
}).join(","))
].join("\n")
console.log(csv)
// → name,age,city
// → Alice,30,Berlin
// → Bob,25,Tokyoimport json, csv, io
json_str = '[{"name":"Alice","age":30,"city":"Berlin"},{"name":"Bob","age":25,"city":"Tokyo"}]'
data = json.loads(json_str)
output = io.StringIO()
writer = csv.DictWriter(output, fieldnames=data[0].keys())
writer.writeheader()
writer.writerows(data)
print(output.getvalue())
# → name,age,city
# → Alice,30,Berlin
# → Bob,25,Tokyo# Using jq to convert JSON array to CSV
echo '[{"name":"Alice","age":30},{"name":"Bob","age":25}]' | \
jq -r '(.[0] | keys_unsorted) as $k | $k, (.[] | [.[$k[]]] ) | @csv'
# → "name","age"
# → "Alice",30
# → "Bob",25
# Using Miller (mlr) for streaming conversion
echo '[{"name":"Alice","age":30}]' | mlr --json --ocsv cat
# → name,age
# → Alice,30package main
import (
"encoding/csv"
"encoding/json"
"fmt"
"os"
)
func main() {
jsonStr := `[{"name":"Alice","age":30},{"name":"Bob","age":25}]`
var data []map[string]interface{}
json.Unmarshal([]byte(jsonStr), &data)
w := csv.NewWriter(os.Stdout)
// Write header
headers := []string{"name", "age"}
w.Write(headers)
// Write rows
for _, row := range data {
record := make([]string, len(headers))
for i, h := range headers {
record[i] = fmt.Sprintf("%v", row[h])
}
w.Write(record)
}
w.Flush()
// → name,age
// → Alice,30
// → Bob,25
}