← 全部文章

如何把 CSV 與 XML 轉成 JSON

在 JavaScript、Python 與瀏覽器把 CSV 與 XML 轉成 JSON。涵蓋 array-of-objects 對應、XML 屬性處理,以及型別轉換的陷阱。

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 的轉換

驗證與格式化結果

轉換完成後,確認輸出格式良好、可讀:

常見問題

怎麼把 CSV 轉成 JSON?

把 CSV 解析成列,再把每列映射成以表頭為鍵的物件 —— Python 用 csv.DictReader,JavaScript 用像 papaparse 這樣的函式庫。記住所有值最初都是字串;型別轉換自己做。

為什麼我 CSV 轉出來的 JSON 全是字串?

CSV 沒有型別 —— 每個欄位都是文字。打開型別自動轉換(例如 papaparse 的 dynamicTyping),或在解析後明確把數字和布林值轉換掉。

把 XML 轉成 JSON 時如何處理 XML 屬性?

大多數轉換器把屬性映射成帶前綴的鍵,例如 @(如 @id)。選一個約定並一致套用,下游程式碼才知道從哪裡讀。

為什麼我的 XML 轉 JSON 有時是物件有時是陣列?

單一子元素映射成值;重複元素映射成陣列。如果消費端期待一致形狀,請把 parser 設定成對某些元素總是當陣列處理。

在你的瀏覽器裡轉換、驗證並格式化