JSON 轉 Excel:四種辦法與它們各自的失真點
結論:巢狀結構、欄位不一致、陣列套陣列,是 JSON 轉表格最容易翻車的三處。四種辦法按「幾分鐘出結果」排序,每個都標清楚會丟什麼。

結論:扁平物件陣列與物件包陣列直接用線上工具最快,需要每週重新整理就上 Power Query,欄位多要清洗用 Python + pandas,要接進流水線再寫 Node 指令碼;動手前一旦發現巢狀或鍵不一致,先定清楚「一行代表什麼」。
轉換本身不難,難的是「轉完之後發現數字變成文字、多層巢狀只剩一層」。選方法之前先看清資料結構,能省掉一次返工。
一、先判斷你的 JSON 屬於哪一類
開啟檔案看最外層:
| 結構 | 樣子 | 轉換難度 |
|---|---|---|
| 扁平物件陣列 | [{"a":1,"b":2},{...}] |
最容易,一行一條記錄 |
| 物件包陣列 | {"data":[{...}],"total":100} |
容易,取 data 那一層 |
| 巢狀物件 | {"user":{"name":"x"}} |
中等,要決定展開還是拼字串 |
| 陣列套陣列 | {"tags":["a","b"]} |
麻煩,一行裝不下,得拆表 |
| 鍵不一致 | 每條記錄的欄位不同 | 麻煩,列會大面積空值 |
前兩類直接轉,成功率接近 100%;後三類先想清楚「一行代表什麼」,否則轉出來的表沒法用。
二、方法一:線上工具(1 分鐘)
開啟 JSON 轉表格,貼上資料 → 選分隔符與表頭 → 匯出 CSV → Excel 開啟。適合幾十行到幾千行、結構規整的資料。
三個必須注意的點:
- 匯出的是 CSV,不是 xlsx。Excel 開啟 CSV 時預設按系統編碼猜,中文可能亂碼。用「資料 → 從文字/CSV」並顯式選 UTF-8 更穩。
- 以
0開頭的編號會掉零。"007"在 CSV 裡是文字,Excel 會自動轉成數字 7。匯入時把該列設為文字,或者在 JSON 裡給它加個字首。 - 長數字會變科學計數法。身份證號、訂單號超過 15 位就會精度丟失,這類欄位在 JSON 裡本來就該是字串,匯入後也要保持文字格式。
三、方法二:Excel 自帶 Power Query(可複用)
資料每週都要更新時,用 Excel 內建的 Power Query,配置一次以後點「重新整理」就行:
- 「資料」→「獲取資料」→「自檔案」→「自 JSON」;
- 選中檔案後進入 Power Query 編輯器,看到的是
List/Record結構; - 點列標題右側的展開圖示,逐層展開巢狀欄位;
- 確認列名與型別後,「關閉並上載」。
好處是巢狀能一層層展開成多列,而且型別可以手動指定;代價是第一次配置需要理解 List 和 Record 的區別——List 是陣列,Record 是物件,展開方向不一樣。
四、方法三:Python + pandas(欄位多、要清洗時)
import pandas as pd
# 物件包陣列:先取到列表那一層
rows = pd.read_json('data.json')['data']
# 巢狀欄位展開成多列
frame = pd.json_normalize(rows, sep='_')
frame.to_excel('out.xlsx', index=False)
json_normalize 的關鍵引數是 sep,它決定巢狀欄位展開後的列名風格,user_name 比 user.name 在 Excel 裡更好用。陣列套陣列(比如 tags)需要額外一步 explode:
frame = frame.explode('tags')
這一步會把一行拆成多行,是唯一能保留「一對多」關係的做法,代價是其餘欄位重複。
五、方法四:Node 指令碼(要接進流水線時)
import { readFileSync, writeFileSync } from 'node:fs';
const rows = JSON.parse(readFileSync('data.json', 'utf8'));
const headers = [...new Set(rows.flatMap((row) => Object.keys(row)))];
const escapeCell = (value) => `"${String(value ?? '').replaceAll('"', '""')}"`;
const lines = [
headers.join(','),
...rows.map((row) => headers.map((key) => escapeCell(row[key])).join(',')),
];
writeFileSync('out.csv', '\uFEFF' + lines.join('\n'), 'utf8');
兩個細節別省:開頭寫 \uFEFF(BOM)讓 Excel 認 UTF-8;單元格里的雙引號要成對轉義成 "",否則列會錯位。
六、轉換一定會丟的三樣東西
| 丟失項 | 表現 | 補救 |
|---|---|---|
| 型別資訊 | 數字、布林都變成文字或 TRUE/FALSE |
匯入後手動設列型別,或用 Power Query 指定 |
| 巢狀層級 | 深層欄位被壓成 [object Object] |
用 json_normalize 或逐層展開,別直接 String(obj) |
| 一對多關係 | 陣列被塞進一個單元格 | explode 拆行,或單獨建一張關聯表 |
另外,null 與「欄位不存在」在表裡看起來一樣(都是空單元格),但業務含義不同。需要區分時,在 JSON 裡把 null 顯式轉成字串 "null",或者加一列 _has_field 標記。
七、回頭驗證:別隻看第一行
轉完至少抽查三處:
- 記錄條數:CSV 行數應等於陣列長度 + 1(表頭),少一條通常是末尾換行被吞;
- 空值率最高的列:空得多說明鍵名不一致,回去看原始 JSON 是不是有兩種寫法(
userId與user_id); - 最長的那一行:巢狀陣列通常在這裡,確認沒有被截斷。
需要反向操作(Excel/CSV 轉回 JSON)時,用 CSV 轉 JSON,注意表頭會被當作鍵名,改表頭等於改欄位名。
常見問題
線上工具、Power Query 與 pandas 該如何取捨?
線上工具適合幾十行到幾千行、結構規整、只轉一次的資料,貼上後選分隔符與表頭即可匯出 CSV。Power Query 配置一次後點重新整理就行,適合每週都要更新的資料。欄位多、需要清洗時用 Python + pandas 的 json_normalize,要接進流水線再寫 Node 指令碼。
為什麼轉成 CSV 後中文會亂碼?
線上工具匯出的是 CSV 而不是 xlsx,Excel 開啟 CSV 時會按系統編碼猜,UTF-8 無 BOM 的中文就會亂碼。匯出時在開頭寫 \uFEFF(BOM),或在 Excel 裡用「資料 → 從文字/CSV」並顯式選擇 UTF-8。
能否保留原始 JSON 的巢狀層級?
可以,但要逐層展開而不是轉成字串:Power Query 能點列標題的展開圖示一層層展開成多列,pandas 用 json_normalize 配合 sep 把巢狀欄位拆成列。深層欄位直接 String(obj) 只會得到 [object Object],陣列套陣列還要額外做一步 explode。