CSV 和 XML 到處都是 —— 試算表匯出、老 API、企業 feed —— 但大多數現代程式碼想要的是 JSON。一旦你理解了映射規則和那些坑(CSV 裡的一切都是字串;XML 屬性和重複元素需要特殊處理),轉換就很直接。本指南涵蓋 JavaScript、Python 和瀏覽器裡兩個方向的轉換。
範圍: 本文是把 CSV → JSON 與 XML → JSON 放在一起講的廣泛 how-to。如果你需要專門講 XML —— 屬性、文字節點、重複元素、命名空間這些細節 —— 請看 XML 到 JSON 的轉換:屬性、文字節點、陣列與命名空間。反方向請見 JSON 到 XML。
把 CSV 轉成 JSON
一份 CSV 檔案是一列列的逗號分隔值,通常帶一列表頭。自然的 JSON 表示是一個物件陣列,每列一個物件,用表頭做鍵:
# CSV
id,name,active
1,Ada,true
2,Bob,false// JSON
[
{ "id": "1", "name": "Ada", "active": "true" },
{ "id": "2", "name": "Bob", "active": "false" }
] 注意每個值都是字串 —— CSV 沒有型別。把 "1" 轉成數字、把 "true" 轉成布林值,是你必須有意識地做的另一步型別轉換。
在 JavaScript 裡把 CSV 轉成 JSON
對可信、簡單的 CSV,你可以手動 split —— 但真實世界的 CSV 有帶引號的欄位、欄位裡有逗號和換行,所以正式環境用一個像樣的 parser,例如 papaparse:
// 最簡 parser —— 只對簡單、無引號的 CSV 安全
function csvToJson(csv) {
const [header, ...rows] = csv.trim().split('\n');
const keys = header.split(',');
return rows.map((row) => {
const values = row.split(',');
return Object.fromEntries(keys.map((k, i) => [k, values[i]]));
});
}
// 正式 —— 處理引號、內嵌逗號、換行
import Papa from 'papaparse';
const result = Papa.parse(csvText, { header: true, dynamicTyping: true });
// dynamicTyping 會自動把 "1" → 1、"true" → true在 Python 裡把 CSV 轉成 JSON
import csv, json
with open('data.csv', newline='') as f:
rows = list(csv.DictReader(f)) # 用表頭做鍵的 dict 清單
print(json.dumps(rows, indent=2))把 XML 轉成 JSON
XML 比較棘手,因為它有 JSON 沒有的概念:屬性、文字節點,以及「單次出現 vs 重複出現」的元素。沒有唯一「正確」的映射,挑一個約定並一致地套用就好。
<!-- XML -->
<user id="1">
<name>Ada</name>
<role>admin</role>
<role>editor</role>
</user>// 一個常見的 JSON 映射
{
"user": {
"@id": "1", // 屬性,前綴 @
"name": "Ada", // 單一子元素 → 值
"role": ["admin", "editor"] // 重複子元素 → 陣列
}
}在 JavaScript 裡把 XML 轉成 JSON
import { XMLParser } from 'fast-xml-parser';
const parser = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: '@' });
const obj = parser.parse(xmlString);
// 在瀏覽器裡你也可以用 DOMParser 並手動走訪節點樹。在 Python 裡把 XML 轉成 JSON
import xmltodict, json
doc = xmltodict.parse(xml_string) # 屬性會變成 "@name" 鍵
print(json.dumps(doc, indent=2))要小心的映射坑
- 型別會遺失。 CSV 和 XML 的值過來都是字串。明確地把數字和布林值轉型 —— 別假設 parser 已經替你做了。
- 單一 vs 重複元素。 一個
<role>變成一個值;兩個則變成陣列。決定某個欄位是不是要永遠當陣列,免得讓消費端措手不及。 - 屬性 vs 子元素。選一個前綴約定(常見的是
@)並寫進文件。 - 空值與空白。 空的 XML 元素和 CSV 末尾的逗號,依據 parser 不同可能會產生
null、""或者直接缺鍵。
BOM 與編碼怪癖
從 Excel 與某些 Windows 工具匯出的檔案會以 UTF-8 BOM 開頭(0xEF 0xBB 0xBF)。解析前先把它剝掉,不然你的第一個表頭/元素名稱會默默帶著它。RFC 8259 禁止 JSON 開頭出現 BOM,所以你寫的轉換器應該把它從輸入移除,而不是抄到輸出裡。
TSV vs CSV(以及其他分隔符)
「CSV」不一定都是逗號分隔。製表符分隔值(TSV)在工程管線裡很常見,因為 tab 幾乎不會出現在欄位值裡,可以省掉整套引號機制。歐洲版 Excel 匯出常用 ;。如果你看到輸出擠成一欄怪樣子,那就是檔案使用的分隔符和你 parser 預期的不一樣 —— 換一下分隔符,或者用一個能自動偵測的函式庫。
XML 命名空間
XML 元素可以帶命名空間前綴(例如 <soap:Envelope>),由 xmlns 宣告綁定。JSON 沒有命名空間概念,因此大多數轉換器會走三條路之一:把前綴保留在鍵裡("soap:Envelope")、剝掉它,或者把 xmlns 宣告存成 @xmlns:* 屬性。保留前綴是唯一無損的選項。深入內容請見 XML 到 JSON 的轉換。
驗證與格式化結果
轉換完成後,確認輸出格式良好、可讀:
- 用 JSON 驗證器 確認可解析 —— 參見 如何驗證 JSON。
- 美化列印以便 review —— 參見 如何格式化 JSON。
- 如果轉換產出的 JSON 不完全合法(單引號、尾逗號), JSON Fix 可以立刻修好。
常見問題
怎麼把 CSV 轉成 JSON?
把 CSV 解析成列,再把每列映射成以表頭為鍵的物件 —— Python 用 csv.DictReader,JavaScript 用像 papaparse 這樣的函式庫。記住所有值最初都是字串;型別轉換自己做。
為什麼我 CSV 轉出來的 JSON 全是字串?
CSV 沒有型別 —— 每個欄位都是文字。打開型別自動轉換(例如 papaparse 的 dynamicTyping),或在解析後明確把數字和布林值轉換掉。
把 XML 轉成 JSON 時如何處理 XML 屬性?
大多數轉換器把屬性映射成帶前綴的鍵,例如 @(如 @id)。選一個約定並一致套用,下游程式碼才知道從哪裡讀。
為什麼我的 XML 轉 JSON 有時是物件有時是陣列?
單一子元素映射成值;重複元素映射成陣列。如果消費端 期待一致形狀,請把 parser 設定成對某些元素總是當陣列處理。
在你的瀏覽器裡轉換、驗證並格式化
- 如何把 JSON 轉成 CSV(與反向) —— 反方向,附一鍵轉換
- JSON 轉 CSV 轉換器 —— 在瀏覽器裡 JSON ⇄ CSV 互轉
- XML 到 JSON 的轉換 —— 屬性、文字節點、陣列、命名空間深入講解
- JSON 到 XML —— 反方向,附 JSON ⇄ XML 轉換器
- JSON 驗證器 —— 確認你轉出來的 JSON 合法
- JSON Fix —— 修復不完全合法的轉換器輸出
- 如何格式化 JSON —— 美化列印結果
- 什麼是 JSON? —— 目標格式的型別與規則