YAML在Go语言中的自定义标签

huangapple go评论82阅读模式
英文:

YAML custom tags in Go

问题

我在Go语言中有这些带有自定义标签的嵌套结构体:

type DummyParams struct {
  Param1 string `yaml:"param1"`
  Param2 string `yaml:"param2"`
}

type Dummy struct {
  Name   string       `yaml:"name"`
  Type   string       `yaml:"type"`
  Params DummyParams  `yaml:"params"`
}

我创建了一些Dummy的实例并将它们添加到一个切片中:

dummies := make([]Dummy, 0)
dummy1 := Dummy{
    Name: "a",
    Type: "type a",
    Params: DummyParams{
        Param1: "foo",
        Param2: "bar",
    },
}
dummies = append(dummies, dummy1)
dummy2 := Dummy{
    Name: "b",
    Type: "type b",
    Params: DummyParams{
        Param1: "foo",
        Param2: "bar",
    },
}
dummies = append(dummies, dummy2)

最后,我将数据编组并写入文件:

yamlData, err := yaml.Marshal(&dummies)
// 处理错误...
writeErr := os.WriteFile("foo.yaml", yamlData, 0644)
// 处理写入错误...

但是,我得到的yaml文件中的标签名并不是小写的,而是大写的结构体名。有人知道为什么会这样,并且如何修复吗?

英文:

I have these nested structs in Go with custom tags for their properties,

type DummyParams struct {
  Param1 string `yaml:"param1"`
  Param2 string `yaml:"param2"`
}

type Dummy struct {
  Name string `yaml:"name"`
  Type string `yaml:"type"`
  Params DummyParams `yaml:"params"`
}

I create some instances of Dummy and add them to a slice,

dummies := make([]Dummy, 0)
dummy1 := Dummy {
    Name: "a"
    Type: "type a"
    Params: DummyParams {
        Param1: "foo"
        Param2: "bar"
    }
}
dummies = append(dummies, dummy1)
dummy2 := Dummy {
    Name: "b"
    Type: "type b"
    Params: DummyParams {
        Param1: "foo"
        Param2: "bar"
    }
}
dummies = append(dummies, dummy2)

Finally I marshal the data and write it to file

yamlData, err := yaml.Marshal(&dummies)
// handle error ...
writeErr := os.WriteFile("foo.yaml", yamlData, 0644)
// handle write error ...

But the yaml I am getting does not have the lower case tagged names, instead it has the upper case Struct names.
Anybody know why this is happening and how to fix it?

答案1

得分: 2

归咎于你使用的yaml实现。例如,如果你使用gopkg.in/yaml.v3,它可以正常工作。你可以在Go Playground上尝试一下。因此,一种解决方案是使用另一个YAML实现,比如gopkg.in/yaml.v3

你在评论中提到你正在使用https://pkg.go.dev/sigs.k8s.io/yaml@v1.3.0。它的包文档中说:

简而言之,该库首先使用go-yaml将YAML转换为JSON,然后使用json.Marshaljson.Unmarshal将其转换为结构体。这意味着它有效地重用了JSON结构标签以及自定义的JSON方法MarshalJSONUnmarshalJSON,与go-yaml不同。

因此,sigs.k8s.io/yaml@v1.3.0首先将其编组为JSON。如果你想要小写的字段名,可以使用json标签而不是yaml标签:

import "sigs.k8s.io/yaml"

type DummyParams struct {
    Param1 string `json:"param1"`
    Param2 string `json:"param2"`
}

type Dummy struct {
    Name   string      `json:"name"`
    Type   string      `json:"type"`
    Params DummyParams `json:"params"`
}

通过这个改变,输出将包含小写的字段名(在Go Playground上尝试一下):

- name: a
  params:
    param1: foo
    param2: bar
  type: type a
- name: b
  params:
    param1: foo
    param2: bar
  type: type b

请注意,不得不使用json标签而不是yaml标签来使其工作只是sigs.k8s.io/yaml@v1.3.0包的一个怪癖。如果你想要使其与这个包和其他yaml实现一起工作,你可以同时提供jsonyaml标签:

type DummyParams struct {
    Param1 string `json:"param1" yaml:"param1"`
    Param2 string `json:"param2" yaml:"param2"`
}

type Dummy struct {
    Name   string      `json:"name" yaml:"name"`
    Type   string      `json:"type" yaml:"type"`
    Params DummyParams `json:"params" yaml:"params"`
}
英文:

Blame it on the yaml implementation you're using. If you use gopkg.in/yaml.v3 for example, it works. Try it on the Go Playground. So one solution is to use another YAML implementation, such as gopkg.in/yaml.v3.

You mentioned in the comments that you're using https://pkg.go.dev/sigs.k8s.io/yaml@v1.3.0. Its package doc says:

> In short, this library first converts YAML to JSON using go-yaml and then uses json.Marshal and json.Unmarshal to convert to or from the struct. This means that it effectively reuses the JSON struct tags as well as the custom JSON methods MarshalJSON and UnmarshalJSON unlike go-yaml.

So sigs.k8s.io/yaml@v1.3.0 first marshals to JSON. If you want lowercased field names, use json tags instead of yaml tags:

import "sigs.k8s.io/yaml"

type DummyParams struct {
	Param1 string `json:"param1"`
	Param2 string `json:"param2"`
}

type Dummy struct {
	Name   string      `json:"name"`
	Type   string      `json:"type"`
	Params DummyParams `json:"params"`
}

With this change output contains lowercased names (try it on the Go Playground):

- name: a
  params:
    param1: foo
    param2: bar
  type: type a
- name: b
  params:
    param1: foo
    param2: bar
  type: type b

Note that having to use json tags instead of yaml to make it work is just a quirk of the sigs.k8s.io/yaml@v1.3.0 package. If you want to make it work with this package and other yaml implementations, you may provide both json and yaml tags:

type DummyParams struct {
	Param1 string `json:"param1" yaml:"param1"`
	Param2 string `json:"param2" yaml:"param2"`
}

type Dummy struct {
	Name   string      `json:"name" yaml:"name"`
	Type   string      `json:"type" yaml:"type"`
	Params DummyParams `json:"params" yaml:"params"`
}

huangapple
  • 本文由 发表于 2023年5月16日 03:33:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/76257425.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定