Golang如何部分序列化YAML文件

Golang如何部分序列化YAML文件 假设我有一个大致如下的 yaml 文件:

apiVersion: flux.weave.works/v1beta1
kind: HelmRelease
metadata:
  annotations:
    flux.weave.works/ignore: 'false'
    flux.weave.works/automated: 'false'
    flux.weave.works/tag.redash: glob:*
  name: redash
  namespace: default
spec:
  chart:
    git: git@github.com:pkaramol/somerepo.git
    path: charts/myapp
    ref: mybranch
  releaseName: redash
  values:
    namespace: default
    redash-service:
      istio:
        enabled: true
      namespace: default
      image: redash/redash
      tag: 8.0.0.
      imagePullPolicy: Always
      port: 5000
      serviceType: ClusterIP
      env:
        config:
          PYTHONUNBUFFERED: '0'
          REDASH_LOG_LEVEL: 'INFO'
          REDASH_REDIS_URL: 'redis://redis:6379/0'
    redis:
      namespace: default
      istio:
        enabled: true
      replicas: 1
      image: redis
      tag: 5.0-alpine
      port: 6379
      imagePullPolicy: Always
      serviceType: ClusterIP
      resources:
        requests:
          cpu: 200m
          memory: 512Mi
        limits:
          cpu: 1000M
          memory: 1500Mi
    someNode:
    sealedsecrets:
      releaseName_hash: 12345
      anotherNode:
        item1: 
        item2: 
        item3: 
        item4: 

有没有办法只部分地解析它?也就是说,假设我spec.values.sealedsecrets.anotherNode 感兴趣(我认为我应该能把它作为数组或切片获取回来)。

这可能实现吗?


更多关于Golang如何部分序列化YAML文件的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

谢谢,这正是我一直在寻找的。

出于某种原因,似乎找不到可以让我采纳你答案的复选框。

更多关于Golang如何部分序列化YAML文件的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


是的,使用 yaml,你无需解组完整的 YAML。以下代码可行:

package main

import (
    "fmt"
    "gopkg.in/yaml.v2"
    "log"
)

type StructA struct {
    A string `yaml:"a"`
}

type StructB struct {
    StructA `yaml:"a"`
}

var data = `
b: some b
a:
  a: the A
  ignore: me
  c:
    nested: ignored
`

func main() {
    var b StructB

    err := yaml.Unmarshal([]byte(data), &b)
    if err != nil {
        log.Fatalf("error: %v", err)
    }
    fmt.Println(b.A)
}

输出:

the A

在Go中可以使用yaml.v3库的部分解析功能来实现YAML文件的部分序列化。以下是示例代码:

package main

import (
    "fmt"
    "gopkg.in/yaml.v3"
    "io/ioutil"
)

func main() {
    // 读取YAML文件
    data, err := ioutil.ReadFile("config.yaml")
    if err != nil {
        panic(err)
    }

    // 定义只包含所需字段的结构体
    var partial struct {
        Spec struct {
            Values struct {
                SealedSecrets struct {
                    AnotherNode map[string]interface{} `yaml:"anotherNode"`
                } `yaml:"sealedsecrets"`
            } `yaml:"values"`
        } `yaml:"spec"`
    }

    // 部分解析YAML
    err = yaml.Unmarshal(data, &partial)
    if err != nil {
        panic(err)
    }

    // 访问目标数据
    anotherNode := partial.Spec.Values.SealedSecrets.AnotherNode
    fmt.Printf("anotherNode: %v\n", anotherNode)
    
    // 如果需要将anotherNode转换为切片
    var items []interface{}
    for key, value := range anotherNode {
        items = append(items, map[string]interface{}{
            "key":   key,
            "value": value,
        })
    }
    fmt.Printf("作为切片: %v\n", items)
}

或者使用更灵活的方式,通过yaml.Node进行手动解析:

package main

import (
    "fmt"
    "gopkg.in/yaml.v3"
    "io/ioutil"
)

func main() {
    data, err := ioutil.ReadFile("config.yaml")
    if err != nil {
        panic(err)
    }

    var root yaml.Node
    err = yaml.Unmarshal(data, &root)
    if err != nil {
        panic(err)
    }

    // 手动遍历节点查找目标路径
    var targetNode *yaml.Node
    findNode(&root, []string{"spec", "values", "sealedsecrets", "anotherNode"}, 0, &targetNode)

    if targetNode != nil {
        // 解析目标节点
        var result map[string]interface{}
        err = targetNode.Decode(&result)
        if err != nil {
            panic(err)
        }
        fmt.Printf("anotherNode: %v\n", result)
    }
}

func findNode(node *yaml.Node, path []string, depth int, result **yaml.Node) {
    if depth >= len(path) {
        *result = node
        return
    }

    if node.Kind == yaml.MappingNode {
        for i := 0; i < len(node.Content); i += 2 {
            keyNode := node.Content[i]
            valueNode := node.Content[i+1]
            
            if keyNode.Value == path[depth] {
                findNode(valueNode, path, depth+1, result)
                return
            }
        }
    }
}

如果需要将anotherNode的内容作为数组处理,可以这样解析:

package main

import (
    "fmt"
    "gopkg.in/yaml.v3"
)

func main() {
    yamlStr := `...` // 你的YAML内容
    
    var config map[string]interface{}
    err := yaml.Unmarshal([]byte(yamlStr), &config)
    if err != nil {
        panic(err)
    }

    // 使用类型断言安全地访问嵌套字段
    spec, _ := config["spec"].(map[string]interface{})
    values, _ := spec["values"].(map[string]interface{})
    sealedSecrets, _ := values["sealedsecrets"].(map[string]interface{})
    anotherNode, _ := sealedSecrets["anotherNode"].(map[string]interface{})

    // 转换为切片
    var sliceResult []map[string]interface{}
    for k, v := range anotherNode {
        sliceResult = append(sliceResult, map[string]interface{}{
            "key":   k,
            "value": v,
        })
    }
    
    fmt.Printf("作为切片: %v\n", sliceResult)
}

这些方法都能实现YAML文件的部分解析,只提取spec.values.sealedsecrets.anotherNode部分的数据。第一种方法最简洁,直接通过定义部分结构体来解析;第二种方法最灵活,可以处理动态路径;第三种方法适合处理不确定结构的YAML数据。

回到顶部