首页 > 解决方案 > YAML 解析解组失败

问题描述

我已经阅读了很多帖子,但经过多个小时的研究和尝试后仍然无法修复它,这是我的问题。

我有这个 YAML 文件:

---
filename: "Filename.txt"
steps:
  -
    mutationRaw:
      name: "Random things..."
      pattern: "12 34 56 78 9a bc de f0"
      mask: "xxxxxxxx"
      offset: 0
      replace: "f0 de bc 9a 78 56 34 12"
  -
    mutationRaw:
      name: "Some other random things..."
      pattern: "00 00 12 34 56 78 9a bc de f0"
      mask: "xxxxxxxxxx"
      offset: 2
      replace: "11 11 f0 de bc 9a 78 56 34 12"

这是我的 Go 代码:

package main

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

type patcherT struct {
    Filename string `yaml:"filename"`
    Steps    struct {
        MutationsRaw []struct {
            Name      string `yaml:"name"`
        } `yaml:"mutationRaw,omitempty"`
    } `yaml:"steps"`
}

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

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

    fmt.Println("Patcher for ", patcher.Filename)
    fmt.Println("Steps :")
    for i := 0; i < len(patcher.Steps.MutationsRaw); i++ {
        fmt.Println("\t- ", patcher.Steps.MutationsRaw[i].Name)
    }
}

而这个错误:

第 4 行:不能将 !!seq 解组为 struct { MutationsRaw []struct { Name string "yaml:"name"" } "yaml:"mutationRaw,omitempty"" }

请注意,除了mutationRaw 之外,还可以使用mutationFile、deletionRaw、deletionFile 等。我可以这样做:

type patcherT struct {
    Filename string `yaml:"filename"`
    Steps    []struct {
        MutationsRaw struct {
            Name      string `yaml:"name"`
        } `yaml:"mutationRaw,omitempty"`
    } `yaml:"steps"`
}

但是,如果我保持相同的 YAML 结构,我会丢失太多信息。我真的很希望能够patcherT通过patcher.Steps.MutationRaw[i], patcher.Steps.MutationFile[i], ... 解析我的结构,第一个结构使这种解析成为可能,但不起作用,而第二个结构使这种解析更难并且需要 YAML 更改,但可以。

简而言之,我如何解析这样的 YAML 结构以允许我不是在 Steps 上迭代,而是在 MutationsRaw(或 MutationsFile,...)上进行迭代?

标签: goyaml

解决方案


您可以在方法中使用自定义解组逻辑实现yaml.Unmarshaler接口。UnmarshalYAML

例如:

type patcherT struct {
    Filename string `yaml:"filename"`
    Steps   Steps `yaml:"steps"`
}

type Steps struct {
    MutationsRaw []struct {
        Name string `yaml:"name"`
    } `yaml:"mutationRaw,omitempty"`
}

func (s *Steps) UnmarshalYAML(unmarshal func(interface{}) error) error {
    var tmpSteps []struct {
        TmpMutationsRaw struct {
            Name string `yaml:"name"`
        } `yaml:"mutationRaw,omitempty"`
    }
    err := unmarshal(&tmpSteps)
    if err != nil {
        return err
    }
    *s = Steps{MutationsRaw: make([]struct {
        Name string `yaml:"name"`
    }, len(tmpSteps))}
    for i, val := range tmpSteps {
        s.MutationsRaw[i] = struct {
            Name string `yaml:"name"`
        }(struct{ Name string }{Name: val.TmpMutationsRaw.Name})
    }
    return nil
}

PLAYGROUND


推荐阅读