3种实用方法!快速实现XML转JSON,附代码示例

原创 发布日期:
21

一、为什么需要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脚本、数据处理、快速原型开发。是最推荐的首选方案。

XML转JSON


三、方法二: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工具

XML转JSON工具

工具类型: 开发工具
使用次数: 30
JSON转XML工具

JSON转XML工具

工具类型: 开发工具
使用次数: 31
打赏
THE END
作者头像
fuwa
我爱我的参差不齐 我即是自己的反义词