合并来自 YAML 文件的两个映射层次结构,保留所有键

2024年 2月 11日 66.7k 0

合并来自 yaml 文件的两个映射层次结构,保留所有键

php小编西瓜在这篇文章中将要介绍如何合并来自 YAML 文件的两个映射层次结构,并保留所有键。这个过程非常简单,只需要使用适当的函数和方法即可完成。通过合并两个映射层次结构,我们可以将它们的键和值组合在一起,以创建一个更大、更全面的映射层次结构。无论您是在处理配置文件还是在进行数据处理,合并映射层次结构都是一个非常有用的技巧。接下来,我们将一步步为您介绍这个过程,让您轻松掌握这个技巧。

问题内容

我正在研究涉及 yaml 文件中的嵌套键的解决方案。软件将读取参数中传递的文件并按照更新/添加密钥的顺序加载它们。

我有 2 个 yaml 文件,我想合并它们而不丢失任何密钥。我想堆叠所有配置文件以生成单个地图而不删除任何键。

所以我有 yaml 1

env: test1
template:
app:
database:
name: oracle

登录后复制

yaml2

env: test2
template:
app:
database:
version : 12

登录后复制

我想要的结果是(顺序是yaml1 - yaml2)

env: test2
template:
app:
database:
name: oracle
version: 12

登录后复制

我尝试使用地图进行复制,但由于键具有相同的名称,所以我最终得到了

env: test2
template:
app:
database:
version: 12

登录后复制

我正在使用

用于读取 yaml 的 gopkg.in/yaml.v3 为我提供了 map[string] 接口{}

和地图使用复制

package main

import (
"fmt"
"log"
"maps"
"os"
"path/filepath"

"gopkg.in/yaml.v3"
)

type configuration struct {
c m
fl []string
}

type m = map[string]interface{}

func (c *configuration) Update(nc m) {
if c.c == nil {
c.c = nc
} else {
maps.Copy(c.c, nc)
}
}

func (c configuration) Print() {
d, err := yaml.Marshal(&c.c)
if err != nil {
log.Fatalf("error: %v", err)
}
fmt.Printf("---:n%snn", string(d))
}

func (c configuration) ParseDir(path string) {

}

func (c *configuration) LoadFromFile(filename string) {

// YAML string stored in a variable
yf, yfErr := os.ReadFile(filename)

if yfErr != nil {
log.Fatal("Error reading the file ", yfErr)
}
// Map to store the parsed YAML data
var data m

// Unmarshal the YAML string into the data map
err := yaml.Unmarshal(yf, &data)
if err != nil {
log.Fatal(err)
}
c.Update(data)
}

func listFiles(path string) []string {
var returnLf []string
err := filepath.Walk(path,
func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.Mode().IsRegular() {
returnLf = append(returnLf, path)
}
return nil
})
if err != nil {
log.Println(err)
}
return returnLf

}

登录后复制

解决方法

假设您想要合并两个 YAML 文档中以“模板”为键的 YAML 映射,一个相当简单的实现将如下所示:

package main

import (
"fmt"

"gopkg.in/yaml.v3"
)

const data1 = `---
env: test1
template:
app:
database:
name: oracle
foo: whatever
`

const data2 = `---
env: test2
template:
app:
some_stuff: [1, 2, 3, 4]
database:
version : 12
foo: 42
`

type T struct {
Env string `yaml:"env"`
Tmpl map[string]any `yaml:"template"`
}

func mergeMapsRecursively(dst, src map[string]any) map[string]any {
res := make(map[string]any)

for dstKey, dstVal := range dst {
srcVal, exists := src[dstKey]
if !exists {
res[dstKey] = dstVal
continue
}

dstValMap, dstValIsMap := dstVal.(map[string]any)
srcValMap, srcValIsMap := srcVal.(map[string]any)
if dstValIsMap && srcValIsMap {
res[dstKey] = mergeMapsRecursively(dstValMap, srcValMap)
} else {
res[dstKey] = srcVal
}
}

for srcKey, srcVal := range src {
if _, exists := dst[srcKey]; !exists {
res[srcKey] = srcVal
}
}

return res
}

func main() {
var a, b T

if err := yaml.Unmarshal([]byte(data1), &a); err != nil {
panic(err)
}

if err := yaml.Unmarshal([]byte(data2), &b); err != nil {
panic(err)
}

fmt.Printf("%#vn%#vn%#vn", a.Tmpl, b.Tmpl, mergeMapsRecursively(a.Tmpl, b.Tmpl))
}

登录后复制

Playground 链接。

mergeMapsRecursively 函数递归地合并两个映射中存在的字段(如果它们都是映射),或者将 dst 中的值替换为 src 中的值,否则 — 就像 maps.Copy 所做的那样。

如果这不完全是您所要求的,我希望我的示例无论如何都能让您走上正轨。

以上就是合并来自 YAML 文件的两个映射层次结构,保留所有键的详细内容,更多请关注每日运维网(www.mryunwei.com)其它相关文章!

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论