user8557463
user8557463

Reputation:

Parse yaml to struct with dynamic fields

I use the following code to parse yaml to struct which works okay. Now let's assume that I have a struct like install which I know to have two const properties like Name and Group but in addition we can have additional key val properties which could change, you can get any key val properties (dynamic)

How should I define this struct? the idea is to read the yaml file modify some values and write it back (with exact same structure with modified value) to FS, therefore I don't want to miss some dynamically fields which could be in the some yaml file which need to be modified

package main

import (
    "fmt"
    "log"

    "github.com/go-yaml/yaml"
)

type File struct {
    TypeVersion string `yaml:"_type-version"`
    Dependency []Dependency
}

type Dependency struct {
    Name     string
    Type     string
    CWD      string
    Install  []Install
    Requires []Requires
}

type Install struct {
    Name  string
    Group string
   //Here any key value can be
}

type Requires struct {
    Name string
    Type string
}

var data = `
_type-version: "1.0.0"
dependency:
  - name: ui
    type: runner
    cwd: /ui
    install:
       - name: api
         group: test
    requires:
      - name: db
      - type: mongo
      - name: rst
      - name: test
      - name: test2
`

func main() {
    f := File{}

    err := yaml.Unmarshal([]byte(data), &f)
    if err != nil {
        log.Fatalf("error: %v", err)
    }
    fmt.Printf("--- t:\n%v\n\n", f)

    d, err := yaml.Marshal(&f)
    if err != nil {
        log.Fatalf("error: %v", err)
    }
    fmt.Printf("--- t dump:\n%s\n\n", string(d))
}

Example Install can be like above and also like this

    install:
       - name: api
         group: test
         a1:test2
         b1:test2

And also

   install:
           - name: api
             group: test
             z10:123
             zzz:111

And many more fields after name and group

Upvotes: 2

Views: 2327

Answers (1)

IhtkaS
IhtkaS

Reputation: 1424

Map instead of a struct for Install will help to solve the problem.

import (
    "fmt"
    "log"

    "github.com/go-yaml/yaml"
)

type File struct {
    TypeVersion string `yaml:"_type-version"`
    Dependency  []Dependency
}

type Dependency struct {
    Name     string
    Type     string
    CWD      string
    Install  []Install
    Requires []Requires
}

type Install map[string]string

func (i Install) name() string {
    return i["name"]
}

func (i Install) group() string {
    return i["group"]
}

type Requires struct {
    Name string
    Type string
}

var data = `
_type-version: "1.0.0"
dependency:
  - name: ui
    type: runner
    cwd: /ui
    install:
       - name: api
         group: test
    requires:
      - name: db
      - type: mongo
      - name: rst
      - name: test
      - name: test2
`

func main() {
    f := File{}

    err := yaml.Unmarshal([]byte(data), &f)
    if err != nil {
        log.Fatalf("error: %v", err)
    }
    fmt.Printf("--- t:\n%v\n\n", f)

    d, err := yaml.Marshal(&f)
    if err != nil {
        log.Fatalf("error: %v", err)
    }
    fmt.Printf("--- t dump:\n%s\n\n", string(d))
}

Upvotes: 2

Related Questions