Golang解析YAML时遇到问题怎么解决
Golang解析YAML时遇到问题怎么解决 我有以下YAML配置。这里有一些代码仓库(repo1, repo2)和发行版(wheezy-test, centos7等)。
repos:
repo1:
centos6-test:
type: rpm
path: /repo/centos/repo1/centos6-test/x86_64
centos7:
type: rpm
sign: 'Secret123'
path: /repo/centos/repo1/centos7/x86_64
repo2:
wheezy-test:
origin: EvilCorp
label: EvilCorp
path: /repo/debian/repo2/wheezy-test
blacklist:
- -dbg
centos7:
type: rpm
sign: 'Secret123'
path: /repo/debian/repo2/7/1.1/x86_64
blacklist:
- -debuginfo
我推测要解析这个配置,我需要应用类似下面的结构:
type RepoConf struct {
Repos Repos `yaml:"repos"`
}
type Repos struct {
Repo1 Repo1 `yaml:"repo1"`
Repo2 Repo2 `yaml:"repo2"`
}
type Repo1 struct {
Centos6Test Centos6Test `yaml:"centos6-test"`
Centos7 Centos7 `yaml:"centos7"`
}
type Repo2 struct {
WheezyTest WheezyTest `yaml:"wheezy-test"`
Centos7 Centos7 `yaml:"centos7"`
}
type Centos6Test struct {
Type string `yaml:"type"`
Path string `yaml:"path"`
}
type Centos7 struct {
Type string `yaml:"type"`
Sign string `yaml:"sign"`
Path string `yaml:"path"`
}
..........
但是我有太多“repoN”和发行版(wheezy-test, wheezy, centos6/7/8等等)的变体。
是否可以在不为每个仓库和发行版创建不同结构的情况下解析这个YAML配置?或者我必须重构我的YAML配置,使其变成类似这样:
repos:
- repo1:
- name: wheezy
sign: ABC
origin: EvilCorp
label: EvilCorp
path: /somepath/bla1
blacklist:
- bla
- name: wheezy-test
sign: ABC
origin: EvilCorp
label: EvilCorp
path: /somepath/bla2
blacklist:
- lib
- repo2:
- name: centos7
sign: '72B865FD'
path: /somepath/bla3
blacklist:
- lib
非常感谢任何建议。
更多关于Golang解析YAML时遇到问题怎么解决的实战教程也可以访问 https://www.itying.com/category-94-b0.html
3 回复
谢谢,Jeff。我已经使用了您建议的那种结构。
更多关于Golang解析YAML时遇到问题怎么解决的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
能否先解析到 map[string]interface{},然后再将映射转换为你期望的内部结构?
可以使用 map[string]interface{} 或嵌套的 map 结构来动态解析YAML,避免为每个仓库和发行版创建单独的结构体。以下是示例代码:
package main
import (
"fmt"
"gopkg.in/yaml.v3"
)
func main() {
yamlData := `
repos:
repo1:
centos6-test:
type: rpm
path: /repo/centos/repo1/centos6-test/x86_64
centos7:
type: rpm
sign: 'Secret123'
path: /repo/centos/repo1/centos7/x86_64
repo2:
wheezy-test:
origin: EvilCorp
label: EvilCorp
path: /repo/debian/repo2/wheezy-test
blacklist:
- -dbg
centos7:
type: rpm
sign: 'Secret123'
path: /repo/debian/repo2/7/1.1/x86_64
blacklist:
- -debuginfo
`
var config map[string]interface{}
err := yaml.Unmarshal([]byte(yamlData), &config)
if err != nil {
panic(err)
}
repos := config["repos"].(map[string]interface{})
for repoName, repoData := range repos {
fmt.Printf("仓库: %s\n", repoName)
distributions := repoData.(map[string]interface{})
for distName, distData := range distributions {
fmt.Printf(" 发行版: %s\n", distName)
distMap := distData.(map[string]interface{})
for key, value := range distMap {
fmt.Printf(" %s: %v\n", key, value)
}
}
}
}
如果需要类型安全,可以定义部分结构体结合 map 使用:
type RepoConfig struct {
Repos map[string]map[string]Distribution `yaml:"repos"`
}
type Distribution struct {
Type string `yaml:"type,omitempty"`
Sign string `yaml:"sign,omitempty"`
Path string `yaml:"path"`
Origin string `yaml:"origin,omitempty"`
Label string `yaml:"label,omitempty"`
Blacklist []string `yaml:"blacklist,omitempty"`
}
func main() {
yamlData := `...` // 同上YAML数据
var config RepoConfig
err := yaml.Unmarshal([]byte(yamlData), &config)
if err != nil {
panic(err)
}
for repoName, distributions := range config.Repos {
fmt.Printf("仓库: %s\n", repoName)
for distName, dist := range distributions {
fmt.Printf(" 发行版: %s\n", distName)
fmt.Printf(" 路径: %s\n", dist.Path)
if dist.Sign != "" {
fmt.Printf(" 签名: %s\n", dist.Sign)
}
if len(dist.Blacklist) > 0 {
fmt.Printf(" 黑名单: %v\n", dist.Blacklist)
}
}
}
}
这种方法可以处理任意数量的仓库和发行版,无需为每个组合创建单独的结构体。

