【问题标题】:Import yaml to excel将yaml导入excel
【发布时间】:2022-08-04 23:44:02
【问题描述】:

我有以下 .YAML 文件:

Name: Tom
Surname: Smith
Status: Married
Childs:
- ChildName: Willy
  Age: 30
  Grandchild:
  - GrandchildName: John
    Age: 4
  - GrandchildName: Maria
    Age: 3
- ChildName: Arthur
  Age: 40
  Grandchild: N/A

我做了什么:

import openpyxl
import yaml

with open(\'family.yaml\') as file:
    family_list = yaml.load(file, Loader=yaml.FullLoader)

def create_workbook():
    wb = openpyxl.Workbook(\'family.xlsx\')
    wb.save(\'family.xlsx\')

def update_workbook():
    wb = openpyxl.load_workbook(\'family.xlsx\')

    sh1 = wb.active

    for item in family_list.items():
        sh1.append(item)
    wb.save(\'family.xlsx\')

create_workbook()
update_workbook()

此代码允许我将数据(没有“暂停”部分,因此只有姓名、姓氏、状态)添加到 excel 中,但将“姓名”、“姓氏”等添加到 A1 列中(而不是在行中作为我想要)

Final excel workbook I want to get

我不确定如何附加和格式化(每个暂停符号应该是新行)提到的数据。我将不胜感激任何提示!

    标签: python excel yaml openpyxl xlsx


    【解决方案1】:

    由于 Excel 所需的布局,这不是通过 pandas 将数据直接转置到 Excel。可能有几种方法可以做到这一点,我决定将 yaml 加载分成三个字典;
    家长
    孩子
    孙子
    因此可以调整它们以适应 excel 布局。然后使用 Pandas 在适当的行/列位置将这些导出到 Excel。

    此示例已使用添加/减少和重命名的子元素和孙子元素进行了测试,但可能无法处理丢失或不正确的元素。

    代码中说明了它的作用,因此您可以了解此方法的工作原理。

    import pandas as pd
    import yaml
    from yaml.loader import SafeLoader
    
    def write_next_segments(dataf, start_row, startcol):
        header = True
        for ele in dataf:
            dataframe = pd.DataFrame([dataf[ele]])
            dataframe.to_excel(writer, sheet_name=save_sheet,
                               index=False,
                               header=header,
                               startrow=start_row,
                               startcol=startcol)
            if header:
                header = False
                start_row += 2
                adjust_colmns(dataframe, startcol)
            else:
                start_row += 1
    
    
    def adjust_colmns(dataframe, offset):
        for column in dataframe:
            column_width = max(dataframe[column].astype(str).map(len).max(), len(column)) + 2
            col_idx = dataframe.columns.get_loc(column) + offset
            writer.sheets[save_sheet].set_column(col_idx, col_idx, column_width)
    
    # --- Start ---
    yaml_file = 'family.yaml'
    yaml_sub_name = 'Childs'
    save_file = 'family.xlsx'
    save_sheet = 'Sheet1'
    
    
    # Open the file and load the file
    with open(yaml_file) as f:
        yaml_data = yaml.load(f, Loader=SafeLoader)
    
    # Make copy of the original dictionary for modification
    print("------ Copy the Parent dictionary                 -------------")
    parent_dict = yaml_data.copy()
    
    print("------ Create the Child & GrandChild dictionaries -------------")
    # Create new dictionary, 'Child' from the the Parent dictionary using the
    # sub Child elements
    # Also create a new dictionary, 'Grandchild' from the Child dictionary
    # using the sub Grandchild elements
    # Then remove the sub elements from their parent dictionaries
    # Thus creating three dictionaries with just their top level elements
    
    # Set up the Child and Grandchild Headers
    # The first element is the header row and is always empty but needs the
    # Headers for Pandas
    # Extract the header fields from the parent dictionary
    child_dict = {}
    grandchild_dict = {}
    sub_list = ''
    for x in parent_dict[yaml_sub_name][0]:
        if len(child_dict) == 0:
            child_dict['Childs0'] = {x: ''}
        else:
            if type(yaml_data[yaml_sub_name][0][x]) != list:
                child_dict['Childs0'].update({x: ''})
            else:
                sub_list = x
    
    for x in parent_dict[yaml_sub_name][0][sub_list][0]:
        if len(grandchild_dict) == 0:
            grandchild_dict['Grandchilds0'] = {x: ''}
        else:
            grandchild_dict['Grandchilds0'].update({x: ''})
    
    # Remove the Child elements from the Parent dictionary
    child_list = parent_dict.pop(yaml_sub_name)
    
    # Create the rest of the Child and Grandchild dictionaries padding the
    # elements based on their relation to their parent
    # On completion of the dictionary remove the sub elements
    row = 1
    for enum, ele in enumerate(child_list):
        if row != 1: row += 1
        child_dict[yaml_sub_name + str(row)] = ele
        pop_num = row
        if type(child_list[enum][sub_list]) == list:
            for i in range(len(child_list[enum][sub_list])):
                if i == 0:
                    grandchild_dict['Grandchilds' + str(row)] = {'': '', '': ''}
                grandchild_dict['Grandchilds' + str(row + 1)] = ele[sub_list][i]
                row += 1
                child_dict[yaml_sub_name + str(row)] = {'': '', '': ''}
        child_dict[yaml_sub_name + str(pop_num)].pop(sub_list)
    
    # Export dictionaries to excel using Pandas. THe xlsxwriter engine is used to adjust
    # columns width
    print("------ Export dictionaries to Excel using Pandas --------------")
    parent_col_offset = len(parent_dict)
    child_col_offset = len(child_dict['Childs0'])
    column_offset = 0
    writer = pd.ExcelWriter(save_file, engine='xlsxwriter')
    
    df = pd.DataFrame([parent_dict])
    df.to_excel(writer, sheet_name=save_sheet, index=False)
    adjust_colmns(df, column_offset)
    
    write_next_segments(child_dict, 0, parent_col_offset)
    write_next_segments(grandchild_dict, 0, parent_col_offset + child_col_offset)
    
    print("------ Save Excel file to '" + save_file + "' ---------------------")
    writer.save()
    

    【讨论】:

      猜你喜欢
      • 2023-03-22
      • 2018-02-19
      • 2012-08-06
      • 1970-01-01
      • 1970-01-01
      • 2018-08-02
      • 1970-01-01
      相关资源
      最近更新 更多