
在系统间进行数据交换时,你经常会遇到两种主流格式:JSON(JavaScript 对象表示法)和 XML(可扩展标记语言)。虽然 JSON 已成为现代 REST API 的默认选择,但 XML 在企业环境、配置文件(如 Maven 的 pom.xml)、Android 布局、SOAP Web 服务和文档格式(Office Open XML、SVG)中仍然不可或缺。
本文深入探讨 JSON 与 XML 之间转换的实践:何时选择一种而非另一种,如何处理结构差异,以及一个完整的工作示例。如果你需要快速转换,试试我们的 JSON 转 XML 工具。
JSON 与 XML 的主要区别
| 特性 | JSON | XML |
|---|---|---|
| 语法 | 键值对、数组 | 基于标签的标记,支持属性 |
| 数据类型 | 原生:字符串、数字、布尔、null、数组、对象 | 所有值均为字符串;通过 XSD 强制类型 |
| 注释 | 不支持(JSON5/JSONC 支持) | 原生支持 |
| 验证 | 无内置模式(JSON Schema 外部) | DTD、XML Schema (XSD) |
| 解析速度 | 更快(更简洁) | 更慢(更冗长) |
| 文件大小 | 更小 | 更大(冗余标签) |
| 命名空间 | 不支持 | 通过 xmlns 支持 |
| 属性 | 不支持(使用嵌套对象) | 元素上支持 |
何时使用 JSON 与 XML
使用 JSON 的场景:
- 构建 RESTful API 或微服务
- 与 JavaScript 前端交换数据
- 处理轻量级、快速数据传输
- 移动应用或物联网设备
使用 XML 的场景:
- 与企业系统集成(SOAP、遗留 API)
- 创建配置文件(Spring、Maven、Android)
- 表示混合内容文档(如 XHTML、DocBook)
- 需要模式验证和命名空间支持
- 处理 RSS 订阅或 SVG 图形
JSON 与 XML 之间的结构映射
转换两者需要理解每种结构如何映射:
| JSON | XML |
|---|---|
对象 {} |
根元素及子元素 |
数组 [] |
重复元素(或包装元素) |
字符串 "value" |
元素文本内容 |
数字 42 |
元素文本内容(字符串) |
布尔 true |
元素文本内容("true" / "false") |
null |
空元素或省略 |
| 嵌套对象 | 嵌套元素 |
| 无属性概念 | 元素上的属性 |
转换中的常见陷阱
- 单元素数组:JSON
[42]可能变成<item>42</item>(无包装)。确保你的转换器始终生成数组包装以保持一致性。 - 属性与子元素:JSON 没有原生属性。转换器通常使用特殊约定(例如
@attr或_attributes)。提前决定。 - 命名空间处理:XML 命名空间(
xmlns:prefix)没有 JSON 等价物。剥离或编码它们。 - 混合内容:XML 允许文本 + 子元素(例如
<p>Hello <b>world</b></p>)。JSON 需要结构化表示。 - 注释:XML 注释在 JSON 中丢失。如果需要,将其存储为特殊键。
端到端转换示例
假设我们有一个表示图书馆目录的 JSON 对象,想要将其转换为 XML。
输入 JSON:
{
"library": {
"name": "City Library",
"books": [
{
"id": "001",
"title": "Java Fundamentals",
"author": "Alice",
"price": 45.00,
"available": true
},
{
"id": "002",
"title": "Python Data Science",
"author": "Bob",
"price": 55.00,
"available": false
}
]
}
}
目标 XML:
<?xml version="1.0" encoding="UTF-8"?>
<library>
<name>City Library</name>
<books>
<book id="001">
<title>Java Fundamentals</title>
<author>Alice</author>
<price>45.00</price>
<available>true</available>
</book>
<book id="002">
<title>Python Data Science</title>
<author>Bob</author>
<price>55.00</price>
<available>false</available>
</book>
</books>
</library>
应用的转换规则
- 根 JSON 对象
library成为根 XML 元素<library>。 - 每个键值对成为子元素。键是元素名,值是文本内容。
- 数组
books由一个包装元素<books>表示,其中包含重复的<book>元素。 id字段被提升为 XML 属性(按约定)。- 数字和布尔值变为文本字符串。
使用转换器(伪代码)
import json
import xml.etree.ElementTree as ET
def json_to_xml(json_obj, root_name="root"):
root = ET.Element(root_name)
_build_xml(root, json_obj)
return ET.tostring(root, encoding="unicode")
def _build_xml(parent, data):
if isinstance(data, dict):
for key, value in data.items():
# 特殊处理属性:以 '@' 开头的键
if key.startswith('@'):
parent.set(key[1:], str(value))
elif key == '#text':
parent.text = str(value)
else:
child = ET.SubElement(parent, key)
_build_xml(child, value)
elif isinstance(data, list):
for item in data:
# 使用父标签作为每个列表项的元素名(必要时单数化)
item_elem = ET.SubElement(parent, parent.tag.rstrip('s'))
_build_xml(item_elem, item)
else:
parent.text = str(data)
# 使用:
json_input = '{"library": {"name": "City Library", ...}}'
xml_output = json_to_xml(json.loads(json_input), "library")
print(xml_output)
安全与性能考虑
- XML 外部实体(XXE)攻击:解析 XML 时,禁用外部实体解析以防止文件泄露或 SSRF。在 Python 的
xml.etree.ElementTree中,使用defusedxml。 - Billion Laughs 攻击:恶意 XML 使用嵌套实体扩展可能导致拒绝服务。限制实体扩展深度。
- JSON 解析:通常更安全,但注意 JavaScript 环境中的原型污染。
- 大型负载:XML 更冗长;对于批量数据,JSON 可减少带宽。对于超大文件,使用流式解析器(例如 XML 的 SAX,JSON 的
ijson)。
常见问题解答
为什么转换后的 XML 没有属性?
JSON 没有内置属性概念。大多数转换器将所有字段视为子元素。要获得属性,你必须使用一个约定(例如,键前缀 @ 或使用嵌套的 _attributes 对象)。请查阅你的转换器文档。
转换过程中能否保留注释?
标准 JSON 不支持注释。如果需要注释,考虑使用 JSON5 或将它们存储为特殊键(例如 "_comment")。XML 注释在转换为 JSON 时通常会丢失。
如何处理 JSON 中的 XML 命名空间?
命名空间可以表示为包含完整命名空间 URI 的 JSON 键(例如 "xmlns:prefix": "http://example.com/ns"),或者通过将前缀编码到元素名中(例如 "prefix:element")。选择一致的策略。
JSON 转 XML 的最佳工具是什么?
对于一次性转换,我们的 JSON 转 XML 工具 很好用。对于编程使用,像 xmltodict(Python)或 json2xml(Node.js)这样的库很流行。
XML 在 2025 年仍然相关吗?
是的。虽然 JSON 主导 Web API,但 XML 在企业集成(SOAP)、配置(Maven、Android)、文档格式(DOCX、XLSX)以及 SVG 和 RSS 等标准中不可替代。理解两者对任何开发者都至关重要。