为什么需要JSON格式转换?

在现代数据交换中,JSON(JavaScript Object Notation)已成为最流行的数据格式之一。它轻量级、易于阅读和编写,并且被几乎所有编程语言支持。然而,在实际应用中,我们常常遇到需要转换JSON格式的情况:

  • 不同系统间的数据结构不一致
  • API版本升级导致的数据结构变化
  • 数据清洗和预处理需求
  • 优化数据存储结构
  • 适应不同前端框架的数据要求

Python凭借其简洁的语法和强大的数据处理能力,成为JSON格式转换的理想工具。本教程将带你全面掌握Python处理JSON的各种技巧。

Python处理JSON的基础

Python标准库中的json模块提供了处理JSON数据的基本功能。下面是核心的四个方法:

方法 描述 使用场景
json.load() 从文件对象读取JSON数据并转换为Python对象 读取JSON文件
json.loads() 将JSON字符串解析为Python对象 处理API响应中的JSON字符串
json.dump() 将Python对象转换为JSON并写入文件 保存处理结果到文件
json.dumps() 将Python对象转换为JSON字符串 准备发送给API的JSON数据

基本读写操作示例

import json

# 读取JSON文件
with open('data.json', 'r', encoding='utf-8') as f:
    data = json.load(f)

# 修改数据
data['new_key'] = 'new_value'

# 写入JSON文件(格式化输出)
with open('modified_data.json', 'w', encoding='utf-8') as f:
    json.dump(data, f, indent=4, ensure_ascii=False)
重要参数说明:

indent:指定缩进空格数,使输出更易读(设置为None则不格式化)

ensure_ascii:设置为False可正确输出非ASCII字符(如中文)

sort_keys:设置为True可按键名字母顺序排序

常见的JSON转换场景

1. 键名重命名

在不同系统集成时,常常需要将键名改为符合目标系统的命名规范:

# 原始数据
original_data = {
    "first_name": "John",
    "last_name": "Doe",
    "email_addr": "john.doe@example.com"
}

# 键名映射关系
key_mapping = {
    "first_name": "firstName",
    "last_name": "lastName",
    "email_addr": "email"
}

# 转换键名
converted_data = {key_mapping.get(k, k): v for k, v in original_data.items()}

print(converted_data)
# 输出: {'firstName': 'John', 'lastName': 'Doe', 'email': 'john.doe@example.com'}

2. 嵌套结构扁平化

将嵌套的JSON结构转换为扁平结构,便于数据分析:

def flatten_json(data, prefix=''):
    flattened = {}
    for key, value in data.items():
        new_key = f"{prefix}_{key}" if prefix else key
        
        if isinstance(value, dict):
            flattened.update(flatten_json(value, new_key))
        else:
            flattened[new_key] = value
    return flattened

# 嵌套结构示例
nested_data = {
    "person": {
        "name": "Alice",
        "age": 30,
        "address": {
            "street": "123 Main St",
            "city": "Boston"
        }
    },
    "company": "TechCorp"
}

# 执行扁平化
flat_data = flatten_json(nested_data)
print(flat_data)
# 输出: {'person_name': 'Alice', 'person_age': 30, 
#       'person_address_street': '123 Main St', 
#       'person_address_city': 'Boston', 'company': 'TechCorp'}

3. 数据类型转换

处理JSON中不正确的数据类型,如字符串数字转换为数值:

def convert_types(data):
    if isinstance(data, dict):
        return {k: convert_types(v) for k, v in data.items()}
    elif isinstance(data, list):
        return [convert_types(item) for item in data]
    elif isinstance(data, str):
        # 尝试转换为数字
        try:
            return int(data)
        except ValueError:
            try:
                return float(data)
            except ValueError:
                # 尝试转换日期等特殊格式
                return data
    else:
        return data

# 原始数据(所有值都是字符串)
data_str = {
    "id": "12345",
    "price": "29.99",
    "count": "100",
    "is_active": "true",
    "dimensions": {
        "width": "15.5",
        "height": "20.0"
    }
}

converted_data = convert_types(data_str)
print(converted_data)
# 输出: {'id': 12345, 'price': 29.99, 'count': 100, 
#       'is_active': 'true', 'dimensions': {'width': 15.5, 'height': 20.0}}
JSON格式转换工具

输入JSON

转换后JSON

高级转换技巧

使用Pandas处理复杂转换

对于大型数据集或复杂转换,Pandas提供了强大的处理能力:

import pandas as pd

# 从JSON文件创建DataFrame
df = pd.read_json('employees.json', orient='records')

# 复杂转换示例:
# 1. 拆分全名为姓和名
df[['last_name', 'first_name']] = df['full_name'].str.split(', ', expand=True)

# 2. 转换日期格式
df['start_date'] = pd.to_datetime(df['start_date'], format='%Y-%m-%d')

# 3. 计算工作年限
df['years_of_service'] = (pd.Timestamp.now() - df['start_date']).dt.days // 365

# 4. 按部门分组统计
department_stats = df.groupby('department').agg(
    avg_salary=('salary', 'mean'),
    employee_count=('id', 'count')
).reset_index()

# 将结果转换为JSON
result_json = department_stats.to_json(orient='records', indent=4)

使用JMESPath进行高级查询和转换

JMESPath提供了类似SQL的查询语法,可以高效地提取和转换JSON数据:

import jmespath

# 复杂JSON数据
company_data = {
  "company": "TechInnovate",
  "departments": [
    {
      "name": "Engineering",
      "employees": [
        {"name": "Alice", "salary": 95000, "role": "Developer"},
        {"name": "Bob", "salary": 110000, "role": "Team Lead"}
      ]
    },
    {
      "name": "Marketing",
      "employees": [
        {"name": "Charlie", "salary": 85000, "role": "Manager"},
        {"name": "Diana", "salary": 78000, "role": "Specialist"}
      ]
    }
  ]
}

# 使用JMESPath查询:
# 1. 获取所有员工姓名和薪资
expression1 = "departments[*].employees[].[name, salary]"
result1 = jmespath.search(expression1, company_data)
# 结果: [['Alice', 95000], ['Bob', 110000], ['Charlie', 85000], ['Diana', 78000]]

# 2. 获取各部门最高薪资
expression2 = "departments[].[name, max(employees[].salary)]"
result2 = jmespath.search(expression2, company_data)
# 结果: [['Engineering', 110000], ['Marketing', 85000]]

# 3. 获取薪资超过90000的员工
expression3 = "departments[*].employees[?salary > `90000`].name"
result3 = jmespath.search(expression3, company_data)
# 结果: [['Alice', 'Bob']]

最佳实践与性能优化

处理大型JSON文件的技巧
  1. 使用ijson流式解析:对于特别大的JSON文件,使用ijson库可以逐项读取数据,减少内存消耗
  2. 分块处理:将大文件分割为小块分别处理
  3. 避免不必要的转换:只提取需要的数据,减少中间数据量
  4. 使用高效的数据结构:如Pandas DataFrame适合表格数据
  5. 启用C扩展:使用ujson库替代json库,性能提升显著
# 使用ujson提高性能
import ujson

# 读取速度比json快4倍以上
with open('large_file.json', 'r') as f:
    data = ujson.load(f)
    
# 写入速度也比json快
with open('output.json', 'w') as f:
    ujson.dump(data, f)