将 YAML 解组为有序映射

我正在尝试使用Go YAML v3解组以下 YAML 。


model:

  name: mymodel

  default-children:

  - payment


  pipeline:

    accumulator_v1:

      by-type:

        type: static

        value: false

      result-type:

        type: static

        value: 3


    item_v1:

      amount:

        type: schema-path

        value: amount

      start-date:

        type: schema-path

        value: start-date

在管道下是任意数量的有序项目。应该将其解组的结构如下所示:


type PipelineItemOption struct {

        Type string

        Value interface{}

}


type PipelineItem struct {

        Options map[string]PipelineItemOption

}


type Model struct {

        Name string

        DefaultChildren []string `yaml:"default-children"`

        Pipeline orderedmap[string]PipelineItem    // "pseudo code"

}

这如何与 Golang YAML v3 一起使用?在 v2 中有 MapSlice,但在 v3 中没有了。


泛舟湖上清波郎朗
浏览 197回答 2
2回答

慕的地10843

您声称编组到中间体yaml.Node是高度非通用的,但我真的不明白为什么。它看起来像这样:package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "gopkg.in/yaml.v3")type PipelineItemOption struct {&nbsp; &nbsp; &nbsp; &nbsp; Type string&nbsp; &nbsp; &nbsp; &nbsp; Value interface{}}type PipelineItem struct {&nbsp; &nbsp; Name string&nbsp; &nbsp; &nbsp; &nbsp; Options map[string]PipelineItemOption}type Pipeline []PipelineItemtype Model struct {&nbsp; &nbsp; &nbsp; &nbsp; Name string&nbsp; &nbsp; &nbsp; &nbsp; DefaultChildren []string `yaml:"default-children"`&nbsp; &nbsp; &nbsp; &nbsp; Pipeline Pipeline}func (p *Pipeline) UnmarshalYAML(value *yaml.Node) error {&nbsp; &nbsp; if value.Kind != yaml.MappingNode {&nbsp; &nbsp; &nbsp; &nbsp; return fmt.Errorf("pipeline must contain YAML mapping, has %v", value.Kind)&nbsp; &nbsp; }&nbsp; &nbsp; *p = make([]PipelineItem, len(value.Content)/2)&nbsp; &nbsp; for i := 0; i < len(value.Content); i += 2 {&nbsp; &nbsp; &nbsp; &nbsp; var res = &(*p)[i/2]&nbsp; &nbsp; &nbsp; &nbsp; if err := value.Content[i].Decode(&res.Name); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return err&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; if err := value.Content[i+1].Decode(&res.Options); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return err&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return nil}var input []byte = []byte(`model:&nbsp; name: mymodel&nbsp; default-children:&nbsp; - payment&nbsp; pipeline:&nbsp; &nbsp; accumulator_v1:&nbsp; &nbsp; &nbsp; by-type:&nbsp; &nbsp; &nbsp; &nbsp; type: static&nbsp; &nbsp; &nbsp; &nbsp; value: false&nbsp; &nbsp; &nbsp; result-type:&nbsp; &nbsp; &nbsp; &nbsp; type: static&nbsp; &nbsp; &nbsp; &nbsp; value: 3&nbsp; &nbsp; item_v1:&nbsp; &nbsp; &nbsp; amount:&nbsp; &nbsp; &nbsp; &nbsp; type: schema-path&nbsp; &nbsp; &nbsp; &nbsp; value: amount&nbsp; &nbsp; &nbsp; start-date:&nbsp; &nbsp; &nbsp; &nbsp; type: schema-path&nbsp; &nbsp; &nbsp; &nbsp; value: start-date`)func main() {&nbsp; &nbsp; var f struct {&nbsp; &nbsp; &nbsp; &nbsp; Model Model&nbsp; &nbsp; }&nbsp; &nbsp; var err error&nbsp; &nbsp; if err = yaml.Unmarshal(input, &f); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; panic(err)&nbsp; &nbsp; }&nbsp; &nbsp; fmt.Printf("%v", f)}

米琪卡哇伊

对我来说,弄清楚v3期望什么而不是MapSlice. 与@flyx 的回答类似,yaml.Node树需要行走,尤其是它的[]Content.map[string]interface{}这是一个提供更可重用和更整洁的有序的实用程序。(虽然它不像指定的问题那样受到限制。)根据上面的结构,Pipeline一般重新定义:type Model struct {&nbsp; &nbsp; Name string&nbsp; &nbsp; DefaultChildren []string `yaml:"default-children"`&nbsp; &nbsp; Pipeline *yaml.Node}使用实用程序 fn 遍历yaml.Node内容:// fragmentvar model Modelif err := yaml.Unmarshal(&model) ; err != nil {&nbsp; &nbsp; return err}om, err := getOrderedMap(model.Pipeline)if err != nil {&nbsp; &nbsp; return err}for _,k := range om.Order {&nbsp; &nbsp; v := om.Map[k]&nbsp; &nbsp; fmt.Printf("%s=%v\n", k, v)}实用程序 fn:type OrderedMap struct {&nbsp; &nbsp; Map map[string]interface{}&nbsp; &nbsp; Order []string}func getOrderedMap(node *yaml.Node) (om *OrderedMap, err error) {&nbsp; &nbsp; content := node.Content&nbsp; &nbsp; end := len(content)&nbsp; &nbsp; count := end / 2&nbsp; &nbsp; om = &OrderedMap{&nbsp; &nbsp; &nbsp; &nbsp; Map: make(map[string]interface{}, count),&nbsp; &nbsp; &nbsp; &nbsp; Order: make([]string, 0, count),&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; for pos := 0 ; pos < end ; pos += 2 {&nbsp; &nbsp; &nbsp; &nbsp; keyNode := content[pos]&nbsp; &nbsp; &nbsp; &nbsp; valueNode := content[pos + 1]&nbsp; &nbsp; &nbsp; &nbsp; if keyNode.Tag != "!!str" {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; err = fmt.Errorf("expected a string key but got %s on line %d", keyNode.Tag, keyNode.Line)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; var k string&nbsp; &nbsp; &nbsp; &nbsp; if err = keyNode.Decode(&k) ; err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; var v interface{}&nbsp; &nbsp; &nbsp; &nbsp; if err = valueNode.Decode(&v) ; err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; om.Map[k] = v&nbsp; &nbsp; &nbsp; &nbsp; om.Order = append(om.Order, k)&nbsp; &nbsp; }&nbsp; &nbsp; return}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go