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? —— 目标格式的类型和规则