python - 将嵌套的 json 转换为 csv,其中每一行包含最内层的值和所有父值
问题描述
我正在寻找一个 python 脚本,以便能够将嵌套的 json 文件转换为 csv 文件,每个最里面的孩子都有自己的行,其中也包括行中的所有父字段。
我的嵌套 json 看起来:
(注意这只是一小段摘录,有数百个日期/值对)
{
"test1": true,
"test2": [
{
"name_id": 12345,
"tags": [
{
"prod_id": 54321,
"history": [
{
"date": "Feb-2-2019",
"value": 6
},
{
"date": "Feb-3-2019",
"value": 5
},
{
"date": "Feb-4-2019",
"value": 4
}
目标是写入 csv,其中每行显示最内层字段及其所有父项的值。(例如, date
, value
, prod_id
, name_id
, test1
)。基本上为每个日期和值创建一行,包括所有父字段值。
我开始使用这个资源作为基础,但仍然不是我想要完成的:
如何在非递归优雅 Python 中展平深度嵌套的 JSON 对象
我尝试过调整这个脚本,但无法提出解决方案。这似乎是一项相对容易的任务,所以也许我缺少一些东西。
解决方案
您想做的很多事情都是特定于数据格式的。这是使用从您引用的链接资源中显示的“传统递归”解决方案松散派生的函数的东西,因为它可以很好地处理这些数据,因为它没有那么深嵌套并且比迭代方法也说明了更简单。
该flatten_json()
函数返回一个列表,每个值对应于传递给它的 JSON 对象中的键。
请注意,这是 Python 3 代码。
from collections import OrderedDict
import csv
import json
def flatten_json(nested_json):
""" Flatten values of JSON object dictionary. """
name, out = [], []
def flatten(obj):
if isinstance(obj, dict):
for key, value in obj.items():
name.append(key)
flatten(value)
elif isinstance(obj, list):
for index, item in enumerate(obj):
name.append(str(index))
flatten(item)
else:
out.append(obj)
flatten(nested_json)
return out
def grouper(iterable, n):
""" Collect data in iterable into fixed-length chunks or blocks. """
args = [iter(iterable)] * n
return zip(*args)
if __name__ == '__main__':
json_str = """
{"test1": true,
"test2": [
{"name_id": 12345,
"tags": [
{"prod_id": 54321,
"history": [
{"date": "Feb-2-2019", "item": 6},
{"date": "Feb-3-2019", "item": 5},
{"date": "Feb-4-2019", "item": 4}
]
}
]
}
]
}
"""
# Flatten the json object into a list of values.
json_obj = json.loads(json_str, object_pairs_hook=OrderedDict)
flattened = flatten_json(json_obj)
print('flattened:', flattened)
# Create row dictionaies for each (data, value) pair at the end of the list
# flattened values with all of the preceeding fields repeated in each one.
test1, name_id, prod_id = flattened[:3]
rows = []
for date, value in grouper(flattened[3:], 2):
rows.append({'date': date, 'value': value,
'prod_id': prod_id, 'name_id': name_id, 'test1': prod_id})
# Write rows to a csv file.
filename = 'product_tests.csv'
fieldnames = 'date', 'value', 'prod_id', 'name_id', 'test1'
with open(filename, mode='w', newline='') as csvfile:
writer = csv.DictWriter(csvfile, fieldnames)
writer.writeheader() # Write csv file header row (optional).
writer.writerows(rows)
print('"{}" file written.'.format(filename))
这是它打印的内容:
flattened: [True, 12345, 54321, 'Feb-2-2019', 6, 'Feb-3-2019', 5, 'Feb-4-2019', 4]
"product_tests.csv" file written.
这是product_tests.csv
生成的文件的内容:
date,value,prod_id,name_id,test1
Feb-2-2019,6,54321,12345,True
Feb-3-2019,5,54321,12345,True
Feb-4-2019,4,54321,12345,True
推荐阅读
- bash - 使用 bash 和 curl 发送突发/多线程请求
- google-cloud-platform - 如何将谷歌云平台上的文件从一个存储桶压缩到另一个存储桶
- javascript - 从 Angular 中的 REST API 获取 HTTPS 时出错
- reactjs - 我似乎无法在反应中使用钩子
- javascript - 以角度格式化代码标签内的http响应数据
- cloudera - 将数据从一个 Cloudera Impala 移植到另一个需要多长时间?
- docker - docker 容器中的 microk8s
- ios - 在不创建新实例的情况下引用另一个类的变量?
- python - Python 错误 - 从 MySql 数据库中提取值的 Unicode/Ascii 问题
- python-c-api - Python C API:在c中调用python c方法的问题