golang实现函数yamlToStruct(infile,outFile)
问:
golang实现函数yamlToStruct(infile,outFile),将yaml文件格式化成golang的结构体
gpt:
要实现一个将YAML文件格式化成Golang结构体的函数,你可以使用 `yaml` 和 `reflect` 包来处理。首先,你需要使用 `yaml.Unmarshal` 函数将YAML文件解析为一个 `map[string]interface{}` 类型的数据结构。然后,你可以使用递归函数来遍历这个map并生成相应的Golang结构体定义。
以下是一个简单的实现:
```go
package main
import (
"fmt"
"io/ioutil"
"log"
"reflect"
"gopkg.in/yaml.v2"
)
func yamlToStruct(infile, outFile string) error {
// 读取YAML文件内容
yamlData, err := ioutil.ReadFile(infile)
if err != nil {
return err
}
// 解析YAML文件
var data map[string]interface{}
if err := yaml.Unmarshal(yamlData, &data); err != nil {
return err
}
// 生成Golang结构体定义
structCode := generateStructCode("MyStruct", data)
// 将结构体定义写入文件
if err := ioutil.WriteFile(outFile, []byte(structCode), 0644); err != nil {
return err
}
return nil
}
func generateStructCode(structName string, data map[string]interface{}) string {
structCode := fmt.Sprintf("type %s struct {\n", structName)
for key, value := range data {
// 判断值的类型
switch v := value.(type) {
case map[interface{}]interface{}:
// 如果是嵌套map,则递归生成结构体定义
nestedStruct := generateStructCode(toCamelCase(key.(string)), v)
structCode += fmt.Sprintf("\t%s %s\n", toCamelCase(key.(string)), nestedStruct)
default:
// 其他类型直接生成字段定义
structCode += fmt.Sprintf("\t%s %s\n", toCamelCase(key.(string)), reflect.TypeOf(value).String())
}
}
structCode += "}\n"
return structCode
}
func toCamelCase(s string) string {
// 将下划线分隔的单词转换为驼峰式
result := ""
upper := true
for _, c := range s {
if c == '_' {
upper = true
} else {
if upper {
result += string(c - ('a' - 'A'))
upper = false
} else {
result += string(c)
}
}
}
return result
}
func main() {
// 替换为你的YAML文件路径和输出文件路径
infile := "example.yaml"
outFile := "output.go"
err := yamlToStruct(infile, outFile)
if err != nil {
log.Fatal(err)
}
}
```
在这个例子中,`yamlToStruct` 函数接受输入的YAML文件路径和输出的Golang文件路径。它首先读取YAML文件,然后使用 `yaml.Unmarshal` 函数将其解析为一个 `map[string]interface{}`。接着,它调用 `generateStructCode` 函数生成Golang结构体的定义,并将生成的代码写入到输出文件中。 `toCamelCase` 函数用于将下划线分隔的字段名转换为驼峰式。请注意,这个实现是一个简单的示例,可能需要根据实际情况进行调整。
调整后的代码:
package main
import (
"fmt"
"io/ioutil"
"log"
"reflect"
"gopkg.in/yaml.v2"
)
func append(structName string) string {
upName := toCamelCase(structName)
data := fmt.Sprintf(`
var g_%s *%s
func Get%s() *%s {
if g_%s != nil {
return g_%s
}
yamlData, err := ioutil.ReadFile("assets/yaml/%s.yaml")
if err != nil {
return nil
}
g_%s = new(%s)
if err := yaml.Unmarshal(yamlData, g_%s); err != nil {
return nil
}
return g_%s
}`, upName, upName, upName, upName, upName, upName, structName, upName, upName, upName, upName)
return data
}
func yamlToStruct(infile, outFile string, structName string) error {
// 读取YAML文件内容
yamlData, err := ioutil.ReadFile(infile)
if err != nil {
return err
}
// 解析YAML文件
var data map[interface{}]interface{}
if err := yaml.Unmarshal(yamlData, &data); err != nil {
return err
}
// 生成Golang结构体定义
structCode := generateStructCode(toCamelCase(structName), data, 1)
// 将结构体定义写入文件
if err := ioutil.WriteFile(outFile, []byte("package yaml\n"+structCode+append(structName)), 0644); err != nil {
return err
}
return nil
}
func generateStructCode(structName string, data map[interface{}]interface{}, deep int) string {
structCode := fmt.Sprintf("%s struct {\n", structName)
switch deep {
case 1:
structCode = fmt.Sprintf("type %s struct {\n", structName)
case 2: //数组
structCode = fmt.Sprintf("struct{\n")
default:
}
for key, value := range data {
// Check if key is a string
keyStr, ok := key.(string)
if !ok {
// Handle the case where key is not a string (e.g., if YAML has non-string keys)
log.Printf("Skipping key %v of non-string type\n", key)
continue
}
// Determine the type of the value
switch v := value.(type) {
case []interface{}:
// If it's an array, check if it's headers
if len(v) > 0 {
// Check if the first element is a map
if headerMap, ok := v[0].(map[interface{}]interface{}); ok {
// If it's headers, generate struct code for Header type
headerStruct := generateStructCode(toCamelCase(keyStr), headerMap, 2)
structCode += fmt.Sprintf("\t%s []%s `yaml:\"%s\"`\n", toCamelCase(keyStr), headerStruct, keyStr)
continue
}
if _, ok := v[0].(string); ok {
// If it's headers, generate struct code for Header type
structCode += fmt.Sprintf("\t%s []%s `yaml:\"%s\"`\n", toCamelCase(keyStr), "string", keyStr)
continue
}
}
// If it's a regular array, generate struct code for its elements
nestedStruct := generateStructCode(toCamelCase(keyStr), v[0].(map[interface{}]interface{}), 2)
structCode += fmt.Sprintf("\t%s []%s `yaml:\"%s\"`\n", toCamelCase(keyStr), nestedStruct, keyStr)
case map[interface{}]interface{}:
// If it's a nested map, recursively generate struct code
nestedStruct := generateStructCode(toCamelCase(keyStr), v, 0)
//structCode += fmt.Sprintf("\t%s %s `yaml:\"%s\"`\n", toCamelCase(keyStr), nestedStruct, keyStr)
structCode += fmt.Sprintf("\t%s `yaml:\"%s\"`\n", nestedStruct, keyStr)
default:
// For other types, generate field definition with yaml tag
structCode += fmt.Sprintf("\t%s %s `yaml:\"%s\"`\n", toCamelCase(keyStr), reflect.TypeOf(value).String(), keyStr)
}
}
structCode += "}"
return structCode
}
func toCamelCase(s string) string {
// 将下划线分隔的单词转换为驼峰式
result := ""
upper := true
for _, c := range s {
if c == '_' {
upper = true
} else {
if upper {
result += string(c - ('a' - 'A'))
upper = false
} else {
result += string(c)
}
}
}
return result
}
func main() {
// 替换为你的YAML文件路径和输出文件路径
var fileName string
fmt.Print("Path is assets/yaml and Enter the input YAML file name: ")
fmt.Scanln(&fileName)
infile := "assets/yaml/" + fileName + ".yaml"
outFile := "assets/yaml/" + fileName + ".go"
err := yamlToStruct(infile, outFile, fileName)
if err != nil {
log.Fatal(err)
} else {
log.Printf("make success")
}
}