使用部分JSON值作为行标题将JSON转换为CSV

时间:2019-06-11 21:40:01

标签: python json csv

我刚刚开始学习Python,我的任务是将JSON转换为CSV文件,以分号作为定界符并具有三个约束。 我的JSON是:

{"_id": "5cfffc2dd866fc32fcfe9fcc", 
"tuple5": ["system1/folder", "system3/folder"], 
"tuple4": ["system1/folder/text3.txt", "system2/folder/text3.txt"], 
"tuple3": ["system2/folder/text2.txt"], 
"tuple2": ["system2/folder"], 
"tuple1": ["system1/folder/text1.txt", "system2/folder/text1.txt"], 
"tupleSize": 3}

输出CSV的格式应为:

system1                  ;           system2        ;             system3
system1/folder           ;             ~            ;            system3/folder
system1/folder/text3.txt ; system2/folder/text3.txt ;              ~
~                        ; system2/folder/text2.txt ;              ~
~                        ; system2/folder           ;              ~
system1/folder/text1.txt ; system2/folder/text1.txt ;              ~

因此,三个约束条件是tupleSize将指示行数,数组元素的第一部分,即sys1sys2sys3将是数组元素,最后只有属于特定系统的那些元素才会在CSV文件中具有值(其余为~)。

我发现了一些有关Python转换的帖子,例如thisthis。它们都没有与这些相关的任何限制,我无法弄清楚该如何处理。

有人可以帮忙吗?

编辑:我应该提到数组元素是动态的,因此CSV文件中的行标题可能会有所不同。

1 个答案:

答案 0 :(得分:0)

您想要做的是相当实质的,因此,如果这只是Python学习练习,我建议您从更多基本任务开始。

我还认为您已经将大多数人所说的行和列颠倒了,因此请注意,下面的所有内容(包括代码)都以与您在问题中使用它们的方式相反的方式使用它们。

无论如何,下面的代码首先会对数据进行预处理,以确定CSV文件的列或字段名称,并确保按'tupleSize'键所指定的列数或字段数正确。 / p>

假定满足约束条件,然后第二次遍历数据,并从每个键值中提取列/字段值,将它们放入字典中,该字典的内容代表要写入输出文件的行,然后完成后会做到这一点。

已更新

已修改,以删除JSON对象字典中所有以“ _id”开头的键。

import csv
import json
import re


SEP = '/'  # Value sub-component separator.
id_regex = re.compile(r"_id\d*")
json_string = '''
    {"_id1": "5cfffc2dd866fc32fcfe9fc1",
     "_id2": "5cfffc2dd866fc32fcfe9fc2",
     "_id3": "5cfffc2dd866fc32fcfe9fc3",
     "tuple5": ["system1/folder", "system3/folder"],
     "tuple4": ["system1/folder/text3.txt", "system2/folder/text3.txt"],
     "tuple3": ["system2/folder/text2.txt"],
     "tuple2": ["system2/folder"],
     "tuple1": ["system1/folder/text1.txt", "system2/folder/text1.txt"],
     "tupleSize": 3}
'''

data = json.loads(json_string)  # Convert JSON string into a dictionary.

# Remove non-path items from dictionary.
tupleSize = data.pop('tupleSize')
_ids = {key: data.pop(key)
            for key in tuple(data.keys()) if id_regex.search(key)}
#print(f'_ids: {_ids}')
max_columns = int(tupleSize)  # Use to check a contraint.

# Determine how many columns are present and what they are.
columns = set()
for key in data:
    paths = data[key]
    if not paths:
        raise RuntimeError('key with no paths')
    for path in paths:
        comps = path.split(SEP)
        if len(comps) < 2:
            raise RuntimeError('component with no subcomponents')
        columns.add(comps[0])

    if len(columns) > max_columns:
        raise RuntimeError('too many columns - conversion aborted')

# Create CSV file.
with open('converted_json.csv', 'w', newline='') as file:
    writer = csv.DictWriter(file, delimiter=';', restval='~',
                            fieldnames=sorted(columns))
    writer.writeheader()

    for key in data:
        row = {}
        for path in data[key]:
            column, *_ = path.split(SEP, maxsplit=1)
            row[column] = path
        writer.writerow(row)

print('Conversion complete')