首頁 >後端開發 >Golang >使用 Python 將點分隔值轉換為 Go 結構

使用 Python 將點分隔值轉換為 Go 結構

王林
王林轉載
2024-02-10 13:33:081003瀏覽

使用 Python 将点分隔值转换为 Go 结构

php小編柚子在本文中將介紹如何使用Python將點分隔值(如"key1.subkey1.subkey2")轉換為Go語言中的結構體。這個轉換過程對於從設定檔或API回應中提取和處理資料非常有用。我們將使用Python的遞歸函數和Go語言的結構體來實現這個轉換,並給出詳細的程式碼範例和解釋。透過本文的學習,讀者將能夠輕鬆處理和轉換點分隔值,提高資料處理的效率和靈活性。

問題內容

這是對可以更改配置的應用程式的特定要求(特別是 wso2 identity server,因為我正在使用 go 為其編寫 kubernetes 運算子)。但這裡確實不相關。我想創建一個解決方案,允許輕鬆管理大量配置映射以產生 go 結構。這些配置映射在 .csv 中

連結到 .csv - my_configs.csv

我想要, 編寫一個自動產生 go 結構的 python 腳本,這樣對應用程式配置的任何變更都可以透過簡單地執行 python 腳本來建立相應的 go 結構來更新。我指的是應用程式本身的配置。例如,可以變更 csv 中的 toml 鍵名稱/可以新增值。

到目前為止,我已經成功創建了一個 python 腳本,幾乎實現了我的目標。腳本是,

import pandas as pd

def convert_to_dict(data):
    result = {}
    for row in data:
        current_dict = result
        for item in row[:-1]:
            if item is not none:
                if item not in current_dict:
                    current_dict[item] = {}
                current_dict = current_dict[item]
    return result

def extract_json_key(yaml_key):
    if isinstance(yaml_key, str) and '.' in yaml_key:
        return yaml_key.split('.')[-1]
    else:
        return yaml_key

def add_fields_to_struct(struct_string,go_var,go_type,json_key,toml_key):
    struct_string += str(go_var) + " " + str(go_type) + ' `json:"' + str(json_key) + ',omitempty" toml:"' +str(toml_key) + '"` ' + "\n"
    return struct_string

def generate_go_struct(struct_name, struct_data):
    struct_name="configurations" if struct_name == "" else struct_name
    struct_string = "type " + struct_name + " struct {\n"
    yaml_key=df['yaml_key'].str.split('.').str[-1]
    
    # base case: generate fields for the current struct level    
    for key, value in struct_data.items():
        selected_rows = df[yaml_key == key]

        if len(selected_rows) > 1:
            go_var = selected_rows['go_var'].values[1]
            toml_key = selected_rows['toml_key'].values[1]
            go_type=selected_rows['go_type'].values[1]
            json_key=selected_rows['json_key'].values[1]
        else:
            go_var = selected_rows['go_var'].values[0]
            toml_key = selected_rows['toml_key'].values[0]
            go_type=selected_rows['go_type'].values[0]
            json_key=selected_rows['json_key'].values[0]

        # add fields to the body of the struct
        struct_string=add_fields_to_struct(struct_string,go_var,go_type,json_key,toml_key)   

    struct_string += "}\n\n"
    
    # recursive case: generate struct definitions for nested structs
    for key, value in struct_data.items():
        selected_rows = df[yaml_key == key]

        if len(selected_rows) > 1:
            go_var = selected_rows['go_var'].values[1]
        else:
            go_var = selected_rows['go_var'].values[0]

        if isinstance(value, dict) and any(isinstance(v, dict) for v in value.values()):
            nested_struct_name = go_var
            nested_struct_data = value
            struct_string += generate_go_struct(nested_struct_name, nested_struct_data)
    
    return struct_string

# read excel
csv_file = "~/downloads/my_configs.csv"
df = pd.read_csv(csv_file)

# remove rows where all columns are nan
df = df.dropna(how='all')
# create the 'json_key' column using the custom function
df['json_key'] = df['yaml_key'].apply(extract_json_key)

data=df['yaml_key'].values.tolist() # read the 'yaml_key' column
data = pd.dataframe({'column':data}) # convert to dataframe

data=data['column'].str.split('.', expand=true) # split by '.'

nested_list = data.values.tolist() # convert to nested list
data=nested_list 

result_json = convert_to_dict(data) # convert to dict (json)

# the generated co code
go_struct = generate_go_struct("", result_json)

# write to file
file_path = "output.go"
with open(file_path, "w") as file:
    file.write(go_struct)

問題是(查看 csv 的下面部分),

authentication.authenticator.basic
authentication.authenticator.basic.parameters
authentication.authenticator.basic.parameters.showAuthFailureReason
authentication.authenticator.basic.parameters.showAuthFailureReasonOnLoginPage
authentication.authenticator.totp
authentication.authenticator.totp.parameters
authentication.authenticator.totp.parameters.showAuthFailureReason
authentication.authenticator.totp.parameters.showAuthFailureReasonOnLoginPage
authentication.authenticator.totp.parameters.encodingMethod
authentication.authenticator.totp.parameters.timeStepSize

這裡,由於 basictotp 欄位 parameters 重複,因此腳本會混淆自身並產生兩個 totpparameters 結構。預期結果是具有 basicparameterstotpparameters 結構。 csv 的 yaml_key 欄位中存在許多類似的重複單字。

我知道這與 ​​go_var = selected_rows['go_var'].values[1] 中索引被硬編碼為 1 有關,但很難修復此問題。

有人可以指點我一個答案嗎?我認為,

  1. 遞迴函數的問題
  2. 產生 json 的程式碼有問題 可能是此問題的根本原因。

謝謝!

我也嘗試過使用 chatgpt,但由於這與巢狀和遞歸有關,因此 chatgpt 提供的答案不是很有效。

更新

我發現包含 propertiespooloptionsendpointparameters 欄位的行有問題。這是因為它們在 yaml_key 欄位中重複。

解決方法

我能夠解決這個問題。但是,我必須完全使用一種新方法來解決問題,即使用樹資料結構,然後遍歷它。這是背後主要的邏輯 - https://www.geeksforgeeks.org/level-順序樹遍歷/

這是工作的python程式碼。

import pandas as pd
from collections import deque

structs=[]
class TreeNode:
    def __init__(self, name):
        self.name = name
        self.children = []
        self.path=""

    def add_child(self, child):
        self.children.append(child)

def create_tree(data):
    root = TreeNode('')
    for item in data:
        node = root
        for name in item.split('.'):
            existing_child = next((child for child in node.children if child.name == name), None)
            if existing_child:
                node = existing_child
            else:
                new_child = TreeNode(name)
                node.add_child(new_child)
                node = new_child
    return root

def generate_go_struct(struct_data):
    struct_name = struct_data['struct_name']
    fields = struct_data['fields']
    
    go_struct = f"type {struct_name} struct {{\n"

    for field in fields:
        field_name = field['name']
        field_type = field['type']
        field_default_val = str(field['default_val'])
        json_key=field['json_key']
        toml_key=field['toml_key']

        tail_part=f"\t{field_name} {field_type} `json:\"{json_key},omitempty\" toml:\"{toml_key}\"`\n\n"

        if pd.isna(field['default_val']):
            go_struct += tail_part
        else:
            field_default_val = "\t// +kubebuilder:default:=" + field_default_val
            go_struct += field_default_val + "\n" + tail_part

    go_struct += "}\n\n"
    return go_struct

def write_go_file(go_structs, file_path):
    with open(file_path, 'w') as file:
        for go_struct in go_structs:
            file.write(go_struct)

def create_new_struct(struct_name):
    struct_name = "Configurations" if struct_name == "" else struct_name
    struct_dict = {
        "struct_name": struct_name,
        "fields": []
    }
    
    return struct_dict

def add_field(struct_dict, field_name, field_type,default_val,json_key, toml_key):
    field_dict = {
        "name": field_name,
        "type": field_type,
        "default_val": default_val,
        "json_key":json_key,
        "toml_key":toml_key
    }
    struct_dict["fields"].append(field_dict)
    
    return struct_dict

def traverse_tree(root):
    queue = deque([root])  
    while queue:
        node = queue.popleft()
        filtered_df = df[df['yaml_key'] == node.path]
        go_var = filtered_df['go_var'].values[0] if not filtered_df.empty else None
        go_type = filtered_df['go_type'].values[0] if not filtered_df.empty else None

        if node.path=="":
            go_type="Configurations"

        # The structs themselves
        current_struct = create_new_struct(go_type)
        
        for child in node.children:  
            if (node.name!=""):
                child.path=node.path+"."+child.name   
            else:
                child.path=child.name

            filtered_df = df[df['yaml_key'] == child.path]
            go_var = filtered_df['go_var'].values[0] if not filtered_df.empty else None
            go_type = filtered_df['go_type'].values[0] if not filtered_df.empty else None
            default_val = filtered_df['default_val'].values[0] if not filtered_df.empty else None

            # Struct fields
            json_key = filtered_df['yaml_key'].values[0].split('.')[-1] if not filtered_df.empty else None
            toml_key = filtered_df['toml_key'].values[0].split('.')[-1] if not filtered_df.empty else None
            
            current_struct = add_field(current_struct, go_var, go_type,default_val,json_key, toml_key)

            if (child.children):
                # Add each child to the queue for processing
                queue.append(child)

        go_struct = generate_go_struct(current_struct)
        # print(go_struct,"\n")        
        structs.append(go_struct)

    write_go_file(structs, "output.go")

csv_file = "~/Downloads/my_configs.csv"
df = pd.read_csv(csv_file) 

sample_data=df['yaml_key'].values.tolist()

# Create the tree
tree = create_tree(sample_data)

# Traverse the tree
traverse_tree(tree)

非常感謝您的幫忙!

以上是使用 Python 將點分隔值轉換為 Go 結構的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除