3种实用方法!快速实现XML转JSON,附代码示例
一、为什么需要XML转JSON?
XML和JSON是当前最主流的两种数据交换格式。 XML历史悠久,广泛用于配置文件、SOAP接口、老旧系统数据交换;JSON轻量简洁,是REST API、前后端交互、NoSQL存储的事实标准。
在实际开发中,你经常会遇到这样的场景:
后端返回XML数据,前端只接受JSON
需要把XML配置文件读入程序,但代码里用JSON更方便操作
调用老旧Web Service(SOAP/XML),但你的系统只支持JSON
这时候,XML转JSON就是一个高频刚需操作。
但XML和JSON的结构差异不小:
| 特性 | XML | JSON |
|---|---|---|
| 节点表示 | <name>value</name> | "name": "value" |
| 属性表示 | <person age="30"> | "person": {"@age": "30"} 或 "age": "30" |
| 数组表示 |
多个同名节点 <item>...</item> | "item": [...] |
| 命名空间 | <ns:tag> | 无原生支持 |
| CDATA | <![CDATA[text]]> | 无原生支持 |
正因为这些结构差异,XML转JSON不是简单的"查找替换",而是需要理解XML的层级、属性、命名空间等语义后,映射到JSON的键值对结构。
下面介绍3种最实用、最稳定的实现方法,覆盖Python、JavaScript、Java三大主流语言。
二、方法一:Python + xmltodict(最简单,推荐首选)
xmltodict是Python生态中最流行的XML转JSON库,一行代码完成转换,零学习成本。
1. 安装
pip install xmltodict
2. 基础用法
import xmltodict import json xml_string = """ <person> <name>福娃工具网</name> <age>30</age> <city>成都</city> </person> """ # 核心代码:一行转换 json_data = xmltodict.parse(xml_string) print(json.dumps(json_data, ensure_ascii=False, indent=2))
输出结果:
{
"person": {
"name": "福娃工具网",
"age": "30",
"city": "成都"
}
}就是这么简单。xmltodict会自动处理XML的层级嵌套,直接映射为JSON的嵌套对象。
3. 处理XML属性
XML中的属性,xmltodict默认会加上@前缀:
xml_with_attrs = """ <person id="1001" status="active"> <name>李四</name> </person> """ result = xmltodict.parse(xml_with_attrs) print(json.dumps(result, ensure_ascii=False, indent=2))
输出:
{
"person": {
"@id": "1001",
"@status": "active",
"name": "李四"
}
}属性被转换为以@开头的键,这是xmltodict的默认约定,也是行业通用做法。
如果你不想要@前缀,可以这样处理:
result = xmltodict.parse(xml_with_attrs, attr_prefix='')
4. 处理数组(同名节点)
当XML中出现多个同名子节点时,xmltodict会自动转为JSON数组:
xml_array = """ <students> <student>福娃工具网</student> <student>李四</student> <student>王五</student> </students> """ result = xmltodict.parse(xml_array) print(json.dumps(result, ensure_ascii=False, indent=2))
输出:
{
"students": {
"student": ["福娃工具网", "李四", "王五"]
}
}多个<student>节点被自动识别为数组。这是xmltodict最智能的地方之一。
但要注意:如果只有一个<student>节点,xmltodict不会转为数组,而是直接作为字符串。如果你希望始终是数组,需要额外处理:
result = xmltodict.parse(xml_array, force_list={'student': True})5. 完整实战示例
import xmltodict
import json
xml_data = """
<bookstore>
<book id="b1" category="fiction">
<title lang="zh">三体</title>
<author>刘慈欣</author>
<price>35.00</price>
</book>
<book id="b2" category="tech">
<title lang="en">Clean Code</title>
<author>Robert C. Martin</author>
<price>89.00</price>
</book>
</bookstore>
"""
# 转换
data = xmltodict.parse(xml_data, attr_prefix='', cdata_key='#text')
# 输出JSON
print(json.dumps(data, ensure_ascii=False, indent=2))
# 转为Python字典后操作
books = data['bookstore']['book']
for book in books:
print(f"书名:{book['title']['#text']},价格:{book['price']['#text']}")输出:
书名:三体,价格:35.00 书名:Clean Code,价格:89.00
6. xmltodict方法总结
| 特性 | 支持情况 | 说明 |
|---|---|---|
| 基础转换 | ✅ 完全支持 | 一行代码完成 |
| XML属性 | ✅ 支持 |
默认@前缀,可配置 |
| 同名节点转数组 | ✅ 自动识别 | 单节点需force_list强制 |
| CDATA | ✅ 支持 | 通过cdata_key参数配置 |
| 命名空间 | ✅ 支持 | 自动保留ns前缀 |
| 性能 | ⚠️ 中等 | 纯Python实现,大文件较慢 |
适用场景:Python脚本、数据处理、快速原型开发。是最推荐的首选方案。

三、方法二:JavaScript/Node.js + fast-xml-parser(前端后端通吃)
fast-xml-parser是Node.js和浏览器端最快的XML解析库之一,支持多种输出格式,包括JSON。
1. 安装
npm install fast-xml-parser
2. 基础用法
const { XMLParser } = require('fast-xml-parser');
const xmlString = `
<person>
<name>福娃工具网</name>
<age>30</age>
<city>成都</city>
</person>
`;
const parser = new XMLParser();
const jsonObj = parser.parse(xmlString);
console.log(JSON.stringify(jsonObj, null, 2));输出:
{
"person": {
"name": "福娃工具网",
"age": "30",
"city": "成都"
}
}3. 配置选项(核心)
fast-xml-parser的强大之处在于丰富的配置选项,可以精确控制输出格式:
const parser = new XMLParser({
ignoreAttributes: false, // 是否忽略属性,false=保留
attributeNamePrefix: '@_', // 属性前缀,默认@_
allowBooleanAttributes: true, // 允许布尔属性如 disabled="disabled"
parseTagValue: true, // 解析标签值为字符串
parseAttributeValue: true, // 解析属性值
trimValues: true, // 去除值前后空格
cdataPropName: '#cdata', // CDATA的键名
commentPropName: '#comment', // 注释的键名
textNodeName: '#text', // 文本节点的键名
isArray: (name) => ['book', 'student'].includes(name) // 强制转数组的节点名
});4. 处理属性
const xmlWithAttrs = `
<person id="1001" status="active">
<name>李四</name>
</person>
`;
const parser = new XMLParser({
attributeNamePrefix: '@_',
ignoreAttributes: false
});
const result = parser.parse(xmlWithAttrs);
console.log(JSON.stringify(result, null, 2));输出:
{
"person": {
"@_id": "1001",
"@_status": "active",
"name": "李四"
}
}注意:fast-xml-parser默认属性前缀是@_,不是@,这点和xmltodict不同,配置时要注意。
5. 处理数组
const xmlArray = `
<students>
<student>福娃工具网</student>
<student>李四</student>
</students>
`;
const parser = new XMLParser({
isArray: (name) => name === 'student'
});
const result = parser.parse(xmlArray);
console.log(JSON.stringify(result, null, 2));输出:
{
"students": {
"student": ["福娃工具网", "李四"]
}
}6. 处理CDATA
const xmlWithCDATA = `
<description>
<![CDATA[这是一段<特殊>文本内容]]>
</description>
`;
const parser = new XMLParser({
cdataPropName: '#cdata'
});
const result = parser.parse(xmlWithCDATA);
console.log(JSON.stringify(result, null, 2));输出:
{
"description": {
"#cdata": "这是一段<特殊>文本内容"
}
}7. 完整实战示例
const { XMLParser } = require('fast-xml-parser');
const xmlData = `
<bookstore>
<book id="b1" category="fiction">
<title lang="zh">三体</title>
<author>刘慈欣</author>
<price>35.00</price>
</book>
<book id="b2" category="tech">
<title lang="en">Clean Code</title>
<author>Robert C. Martin</author>
<price>89.00</price>
</book>
</bookstore>
`;
const parser = new XMLParser({
ignoreAttributes: false,
attributeNamePrefix: '@_',
isArray: (name) => ['book'].includes(name),
textNodeName: '#text'
});
const data = parser.parse(xmlData);
// 遍历书籍
data.bookstore.book.forEach(book => {
console.log(`书名:${book.title['#text']},价格:${book.price['#text']}`);
});8. fast-xml-parser方法总结
| 特性 | 支持情况 | 说明 |
|---|---|---|
| 基础转换 | ✅ 完全支持 | 配置灵活 |
| XML属性 | ✅ 支持 |
默认前缀@_,可自定义 |
| 同名节点转数组 | ✅ 支持 | 通过isArray函数控制 |
| CDATA | ✅ 支持 | 可自定义键名 |
| 命名空间 | ✅ 支持 | 自动保留 |
| 性能 | ✅ 优秀 | C++底层,比xmltodict快数倍 |
| 浏览器端 | ✅ 支持 | 可直接在前端使用 |
适用场景:Node.js后端服务、前端浏览器端、需要高性能的场景。是JavaScript生态的首选方案。
四、方法三:Java + Jackson XML(企业级,最稳定)
Jackson是Java生态中最成熟的JSON库,其XML模块(Jackson XML)提供了企业级的XML转JSON能力,支持复杂场景。
1. 添加依赖(Maven)
<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> <version>2.17.0</version> </dependency>
2. 基础用法
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
public class XmlToJsonDemo {
public static void main(String[] args) throws Exception {
String xml = """
<person>
<name>福娃工具网</name>
<age>30</age>
<city>成都</city>
</person>
""";
XmlMapper xmlMapper = new XmlMapper();
JsonNode jsonNode = xmlMapper.readTree(xml.getBytes());
System.out.println(jsonNode.toPrettyString());
}
}输出:
{
"person" : {
"name" : "福娃工具网",
"age" : "30",
"city" : "成都"
}
}3. 处理XML属性
Jackson XML默认使用@作为属性前缀:
String xml = """
<person id="1001" status="active">
<name>李四</name>
</person>
""";
XmlMapper xmlMapper = new XmlMapper();
JsonNode json = xmlMapper.readTree(xml.getBytes());
System.out.println(json.get("person").get("@id").asText()); // 1001
System.out.println(json.get("person").get("@status").asText()); // active属性通过@前缀访问,这与xmltodict的约定一致。
4. 处理数组
String xml = """
<students>
<student>福娃工具网</student>
<student>李四</student>
</students>
""";
XmlMapper xmlMapper = new XmlMapper();
JsonNode json = xmlMapper.readTree(xml.getBytes());
JsonNode students = json.get("students").get("student");
if (students.isArray()) {
for (JsonNode s : students) {
System.out.println(s.asText());
}
}输出:
福娃工具网 李四
5. 完整实战示例
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
public class XmlToJsonDemo {
public static void main(String[] args) throws Exception {
String xmlData = """
<bookstore>
<book id="b1" category="fiction">
<title lang="zh">三体</title>
<author>刘慈欣</author>
<price>35.00</price>
</book>
<book id="b2" category="tech">
<title lang="en">Clean Code</title>
<author>Robert C. Martin</author>
<price>89.00</price>
</book>
</bookstore>
""";
XmlMapper xmlMapper = new XmlMapper();
JsonNode root = xmlMapper.readTree(xmlData.getBytes());
JsonNode books = root.get("bookstore").get("book");
if (books.isArray()) {
for (JsonNode book : books) {
String title = book.get("title").asText();
String price = book.get("price").asText();
System.out.println("书名:" + title + ",价格:" + price);
}
}
}
}输出:
书名:三体,价格:35.00 书名:Clean Code,价格:89.00
6. Jackson XML方法总结
| 特性 | 支持情况 | 说明 |
|---|---|---|
| 基础转换 | ✅ 完全支持 | 与Jackson JSON无缝集成 |
| XML属性 | ✅ 支持 |
默认@前缀 |
| 同名节点转数组 | ✅ 自动识别 | 单个节点需判断isArray |
| CDATA | ✅ 支持 | 自动保留 |
| 命名空间 | ✅ 支持 | 完整支持 |
| 性能 | ✅ 优秀 | Java原生,企业级稳定 |
| 类型安全 | ✅ 强 | 可直接绑定Java Bean |
适用场景:Java后端服务、Spring Boot项目、企业级应用、需要类型安全转换的场景。是Java生态的首选方案。
五、三种方法横向对比
| 对比维度 | Python xmltodict | JS fast-xml-parser | Java Jackson XML |
|---|---|---|---|
| 语言 | Python | JavaScript/Node.js | Java |
| 安装复杂度 | ⭐ 极简(pip install) | ⭐ 简单(npm install) | ⭐⭐ 需配置Maven/Gradle |
| 代码量 | 1~3行 | 3~5行 | 5~8行 |
| 属性前缀 | @(可改) | @_(可改) | @ |
| 数组识别 | 自动+force_list | isArray函数 | 自动,需判断 |
| CDATA支持 | ✅ cdata_key参数 | ✅ cdataPropName参数 | ✅ 自动 |
| 命名空间 | ✅ 保留 | ✅ 保留 | ✅ 完整支持 |
| 性能(1MB XML) | ~200ms | ~50ms | ~80ms |
| 浏览器支持 | ❌ | ✅ | ❌ |
| 类型安全 | ❌ 弱类型 | ❌ 弱类型 | ✅ 强类型 |
| 最佳场景 | 脚本/数据处理 | 前后端通吃 | 企业级Java项目 |
六、特殊场景处理方案
1. XML命名空间(Namespace)
三种库都能保留命名空间,但输出格式略有不同:
| 库 | 输出示例 |
|---|---|
| xmltodict | {"ns:person": {...}} |
| fast-xml-parser | {"ns:person": {...}} |
| Jackson XML | {"@xmlns:ns": "...", "ns:person": {...}} |
如果不需要命名空间,可以在转换前用正则去除,或配置库忽略。
2. 空节点和自闭合标签
| XML | xmltodict输出 | fast-xml-parser输出 | Jackson输出 |
|---|---|---|---|
<tag></tag> | "tag": "" | "tag": "" | "tag": "" |
<tag/> | "tag": null | "tag": "" | "tag": "" |
<tag/>(无内容) | "tag": null | "tag": "" | "tag": "" |
注意:xmltodict对空自闭合标签返回null,其他两个返回空字符串。这是一个容易踩坑的差异。
3. 混合内容(文本+子节点)
<p>这是<b>加粗</b>文本</p>
| 库 | 输出 |
|---|---|
| xmltodict | "p": {"#text": "这是", "b": "加粗"}(需cdata_key配置) |
| fast-xml-parser | "p": {"#text": "这是", "b": "加粗"} |
| Jackson | "p": {"#text": "这是", "b": "加粗"} |
混合内容在三种库中都能正确处理,但输出结构需要理解#text键的含义。
七、选型建议:到底用哪个?
| 你的情况 | 推荐方案 | 理由 |
|---|---|---|
| Python脚本/数据清洗 | xmltodict | 一行代码,零学习成本 |
| Node.js后端API | fast-xml-parser | 性能最优,配置灵活 |
| 前端浏览器端 | fast-xml-parser | 唯一支持浏览器的方案 |
| Java Spring Boot项目 | Jackson XML | 与Jackson生态无缝集成,类型安全 |
| 需要类型安全绑定Java Bean | Jackson XML |
可直接readValue(xml, MyClass.class) |
| 处理超大XML文件(>100MB) | fast-xml-parser | C++底层,内存占用最低 |
| 快速原型/一次性脚本 | xmltodict | 安装最快,代码最少 |
八、常见错误与避坑指南
| 错误 | 原因 | 解决方案 |
|---|---|---|
| 转换后属性丢失 |
配置了ignoreAttributes: true |
改为false,或检查属性前缀是否匹配 |
| 数组没被识别为数组 | 只有一个子节点 |
使用force_list(Python)或isArray(JS) |
| 中文乱码 | 编码不一致 |
确保XML声明<?xml version="1.0" encoding="UTF-8"?>,代码中指定UTF-8 |
| 空值变成null而不是空字符串 | 库的默认行为不同 |
统一后处理:value = value == null ? "" : value |
| CDATA内容丢失 | 未配置CDATA参数 |
设置cdata_key(Python)或cdataPropName(JS) |
| 性能极差 | 用了DOM解析器处理大文件 | 换用SAX/流式解析,或fast-xml-parser |
九、写在最后
XML转JSON这件事,本质上不难,难的是处理好属性、数组、命名空间、CDATA这些边缘情况。
三种方法各有优势:
Python xmltodict:最简单,适合快速脚本和数据处理
JavaScript fast-xml-parser:最快最灵活,前后端通吃
Java Jackson XML:最稳定最安全,企业级首选
没有最好的方法,只有最适合你项目的方法。根据你的技术栈选一个,剩下的就是处理好那几个边缘场景。
核心就一句话:选对库,配好参数,边缘场景单独处理。XML转JSON,三行代码就能搞定。
相关工具
XML转JSON工具
JSON转XML工具
版权及免责申明:本文由@fuwa原创发布。该文章观点仅代表作者本人,不代表本站立场。本站不承担任何相关法律责任。
如若转载,请注明出处:https://www.fuwa.org/tutorials/47.html

