8

I’ve created the following YAML file to provide some config which users need to provide:

Environments:
 sys1:
    models:
    - app-type: app1
      service-type: “fds"

    - app-type: app2
      service-type: “era”
 sys2:
    models:
    - app-type: app1
      service-type: “fds"

    - app-type: app2
      service-type: “era"

https://codebeautify.org/yaml-validator/cbb349ec

Here I have:

  1. one environment (root)
  2. the environment contain 1..n sys
  3. Each sys contain 1..n models instance with key app-type

Now I need to parse this YAML file so I try to build a struct type like:

type Environment struct {
    Environment [] sys
}

type sys struct{
    Models    []Properties
}

type Models struct{
    app-type     string      `yaml:"app-type"`
    service-type string      `yaml:"service-type"`
}

Now I try to parse this YAML, and I get an error of index out of range.

My questions are:

1. Do I model the YAML correctly?
2. Do I model the struct correctly?

This is the code:

func main() {
    y := Environments{}

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

data is the yaml.file.

Dave C
  • 7,729
  • 4
  • 49
  • 65
  • 1
    Your Go code and YAML are both invalid, can you please post a [MCVE](https://stackoverflow.com/help/mcve)? – Adrian Aug 09 '18 at 20:29
  • @Adrian - see the link ,the yaml is indeed valid –  Aug 09 '18 at 20:35
  • The YAML at the link isn't the YAML in the question, and the Go code is still invaild. – Adrian Aug 09 '18 at 20:39
  • @Adrian - Done please re-check –  Aug 09 '18 at 20:42
  • 2
    The Go code is still invalid. If you're having an issue with some code, *post that code*. If that code is too large to post, reduce it to the smallest possible code *that reproduces the issue* (i.e. a Minimal, Complete, Verifiable Example), and post *that* code. You may find that in doing so, you're able to resolve your own issue; and if not, then the community will have a working example with which to assist you. – Adrian Aug 09 '18 at 20:49

2 Answers2

13

Try this:

package main

import (
    "fmt"
    "log"

    "gopkg.in/yaml.v2"
)

type Message struct {
    Environments map[string]models `yaml:"Environments"`
}
type models map[string][]Model
type Model struct {
    AppType     string `yaml:"app-type"`
    ServiceType string `yaml:"service-type"`
}

func main() {
    data := []byte(`
Environments:
 sys1:
    models:
    - app-type: app1
      service-type: fds
    - app-type: app2
      service-type: era
 sys2:
    models:
    - app-type: app1
      service-type: fds
    - app-type: app2
      service-type: era
`)
    y := Message{}

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

}
DazWilkin
  • 32,823
  • 5
  • 47
  • 88
  • Thanks a lot, this is exactly what I need, one last question, does i build this yaml structure well ? e.g. , what I need in RT after parsing the yaml file to get for environment `sys1` a model with `key` = `app2` –  Aug 11 '18 at 17:40
  • In addition, please see if you can help also here https://stackoverflow.com/questions/51803219/how-to-update-types-value-in-loop-inside-loop , Thanks! –  Aug 11 '18 at 20:36
1

if you are working in the kubernetes environment (k8s) I would suggest you look at the github.com/kubernetes-sigs/yaml package instead of gopkg.in/yaml.v2. The usage is the same but it looks at the json markers of your struct (which are more widespread than the yaml markers). This makes reading yaml from file, converting it to native go structs much easier

package something

import (
  "io/ioutil"

   grafana "github.com/grafana-operator/grafana-operator/v4/api/integreatly/v1alpha1"

   "k8s.io/apimachinery/pkg/types"
   "sigs.k8s.io/yaml"
)

func getDefaultGrafanaForNS(ns string) (grafana.Grafana, error) {
    yfile, err := ioutil.ReadFile("grafana.yml")

    if err != nil {

        return grafana.Grafana{}, err
    }
    result := grafana.Grafana{}
    err = yaml.Unmarshal([]byte(yfile), &result)
    if err != nil {
        return grafana.Grafana{}, err
    }
    return result, nil

}
m1schka
  • 957
  • 1
  • 9
  • 10