Парсинг различных yaml-файлов для сведения в одну таблицу
Есть несколько yaml-файлов:
файл 1
name: phone1
spec:
type1:
- name: cpu
value: 8 core
- name: RAM
value: 8Gb
type:
- name: ttt1
- name: ttt2
color: gold
файл 2
name: phone2
spec:
type1:
- name: cpu
value: 4 core
- name: RAM
value: 4Gb
type:
- name: ttt3
- name: ttt4
size:
length: 80
height: 10
weight: 40
файл 3
name: phone3
spec:
type1:
- name: cpu
value: 2 core
- name: RAM
value: 2Gb
type:
- name: ttt5
- name: ttt6
Надо их представить в табличном виде, где первый столбец это ключ, а остальные - это значения. Если ключ отсутствует в файле, то ячейка остается пустая
Выглядеть таблица будет примерно так:
Phone | file1 | file2 | file3 |
---|---|---|---|
name | phone1 | phone2 | phone3 |
spec.type1.0.name | cpu | cpu | cpu |
spec.type1.0.value | 8 core | 4 core | 2 core |
spec.type1.1.name | RAM | RAM | RAM |
spec.type1.1.value | 8Gb | 4Gb | 2Gb |
spec.type1.1.type.0.name | ttt1 | ttt3 | ttt5 |
spec.type1.1.type.1.name | ttt2 | ttt4 | ttt6 |
spec.size.length | 80 | ||
spec.size.height | 10 | ||
spec.size.weight | 40 | ||
spec.color | gold |
На самом деле файлов таких много, я лишь привел некоторые примеры из них
пытаюсь их все распарсить: вот пример для одного файла:
import yaml
import pandas as pd
# Загрузка YAML-файла в словарь
def GetData(data, prefix):
if isinstance(data, dict):
for k, v in data.items():
yield from GetData(v, f'{prefix}/{k}')
elif isinstance(data, list):
for i, v in enumerate(data):
yield from GetData(v, f'{prefix}/{i}')
else:
yield (prefix, data)
# Путь к YAML-файлу
def var1(filename: str):
with open(filename, "r") as f:
yaml_data = yaml.safe_load(f)
retval = pd.DataFrame(GetData(yaml_data, ''), columns=['0', filename])
return retval
var1('file1.yaml').to_csv('data.csv', index=False)
Результат:
Phone | file1 |
---|---|
name | phone1 |
spec.type1.0.name | cpu |
spec.type1.0.value | 8 core |
spec.type1.1.name | RAM |
spec.type1.1.value | 8Gb |
spec.type1.1.type.0.name | ttt1 |
spec.type1.1.type.1.name | ttt2 |
spec.color | gold |
Для одного файла все работает, но сложить данные из нескольких файлов не получается.
А вот вариант для нескольких файлов:
import yaml
import pandas as pd
files = ["file1.yaml", "file2.yaml", "file3.yaml"]
def var2(filename: str):
with open(filename, "r") as f:
retval = pd.DataFrame(pd.json_normalize(yaml.safe_load(f))).T
retval = retval.rename(columns={0:filename})
return retval
pd.concat([var2(file) for file in files], axis=1).to_csv('results/data2.csv', index=True)
Результат:
Phone | file1 | file2 | file3 |
---|---|---|---|
name | phone1 | phone2 | phone3 |
spec.type1 | "[{'name': 'cpu', 'value': '8 core'}, {'name': 'RAM', 'value': '8Gb', 'type': [{'name': 'ttt1'}, {'name': 'ttt2'}]}]" | "[{'name': 'cpu', 'value': '4 core'}, {'name': 'RAM', 'value': '4Gb', 'type': [{'name': 'ttt3'}, {'name': 'ttt4'}]}]" | "[{'name': 'cpu', 'value': '2 core'}, {'name': 'RAM', 'value': '2Gb', 'type': [{'name': 'ttt5'}, {'name': 'ttt6'}]}]" |
spec.color | gold | ||
spec.size.length | 80 | ||
spec.size.height | 10 | ||
spec.size.weight | 40 |
Здесь другая проблема, не распарсиваются вложенные ключи.
Помогите с решением: что бы парсились все файлы, каждый вложенный ключ заводился в отдельную строку и пустые ключи тоже отображались в таблице
Ответы (1 шт):
Для структуры с вложенными списками json_normalize
для вашего случая не подойдёт. Просто совместите свою функцию GetData
c pd.concat
, предварительно изменив индекс датафреймов:
def GetData(data, prefix):
if isinstance(data, dict):
for k, v in data.items():
yield from GetData(v, f'{prefix}/{k}')
elif isinstance(data, list):
for i, v in enumerate(data):
yield from GetData(v, f'{prefix}/{i}')
else:
yield (prefix, data)
def var2(file: str):
with open(file, "r") as f:
yaml_data = yaml.safe_load(f)
retval = pd.DataFrame(GetData(yaml_data, '')).set_index(0)
retval = retval.rename(columns={1:file})
return(retval)
files = ["file1.yaml", "file2.yaml", "file3.yaml"]
res = pd.concat([var2(file) for file in files], axis=1)
res:
file1.yaml file2.yaml file3.yaml
0
/name phone1 phone2 phone3
/spec/type1/0/name cpu cpu cpu
/spec/type1/0/value 8 core 4 core 2 core
/spec/type1/1/name RAM RAM RAM
/spec/type1/1/value 8Gb 4Gb 2Gb
/spec/type1/1/type/0/name ttt1 ttt3 ttt5
/spec/type1/1/type/1/name ttt2 ttt4 ttt6
/spec/color gold NaN NaN
/spec/size/length NaN 80 NaN
/spec/size/height NaN 10 NaN
/spec/size/weight NaN 40 NaN