разбирать yaml с глубокой структурой и значением массива - PullRequest
0 голосов
/ 19 марта 2019

я пытаюсь разобрать следующий yaml, и я получил ошибку, yaml действителен в соответствии с https://codebeautify.org/yaml-validator/cb4510d0 Я пытаюсь использовать интерфейс и до сих пор не могу разобрать файл. что мне нужно это:

  1. выведите значения как runner1 runner2 и runner3
  2. значения cmd

есть идеи, почему интерфейс не работает в этом случае?

ошибка:

2019/03/19 22:42:11 Error : yaml: unmarshal errors:
  line 6: cannot unmarshal !!seq into map[string]interface {}
  line 22: cannot unmarshal !!seq into map[string]interface {}

это то, что я пытался

package main

import (
    "fmt"
    "log"

    "gopkg.in/yaml.v2"
)

var runContent = []byte(`
version: "1.1"

run-parameters:
  before:
    - runner: runner1
      options: 
        cmd:
         - value1
         - value2
      supported: k8s

    - runner: runner2
      options: 
        cmd:
         - value3
         - value4
      supported: aws


  after:
    - runner: runner3
      options: 
        cmd:
         - value6
         - value7
      supported: aws


`)

type FTD struct {
    Version     string     `yaml:"version,omitempty"`
    BuildParams *RunParams `yaml:"run-parameters,omitempty"`
}

type RunParams struct {
    BeforeExec map[string]interface{} `yaml:"before,omitempty"`
    AfterExec  map[string]interface{} `yaml:"after,omitempty"`
}

func main() {
    runners := &FTD{}
    // parse mta yaml
    err := yaml.Unmarshal(runContent, runners)
    if err != nil {
        log.Fatalf("Error : %v", err)
    }
    // for _, v := range runners.BuildParams.BeforeExec {
    //  fmt.Printf("%#v\n", v)
    // }

    // fmt.Println(runners.BuildParams.BeforeExec["run-parameters"])

    // if _, ok := runners.BuildParams.BeforeExec["run-parameters"]; ok {
    //  run := runners.BuildParams.BeforeExec["run-parameters"].(map[interface{}]interface{})["run"]
    //  fmt.Println("run: ", run)
    // }

    runParams, ok := runners.BuildParams.BeforeExec["run-parameters"]

    if !ok {
        // handle lack of "run-parameters" in BeforeExec
    }

    runParamsMap, ok := runParams.(map[interface{}]interface{})

    if !ok {
        // handle "run-parameters" not being a map
    }

    run, ok := runParamsMap["run"]

    if !ok {
        // handle lack of "run" inside "run-parameters"
    }

    runStr, ok := run.(string)

    if !ok {
        // handle "run" not being a string
    }

    fmt.Println("run: ", runStr)

}

Ответы [ 3 ]

1 голос
/ 20 марта 2019

Вам нужно изменить

type RunParams struct {
    BeforeExec map[string]interface{} `yaml:"before,omitempty"`
    AfterExec  map[string]interface{} `yaml:"after,omitempty"`
}

разбить на массив карты

type RunParams struct {
    BeforeExec []map[string]interface{} `yaml:"before,omitempty"`
    AfterExec  []map[string]interface{} `yaml:"after,omitempty"`
}

И будут внесены изменения в ваш код для поддержки массива map.

1 голос
/ 20 марта 2019

попробуйте это:

type RunParams struct {
    BeforeExec []Runners `yaml:"before,omitempty"`
    AfterExec  []Runners `yaml:"after,omitempty"`
}

type Runners struct {
    Runner string `yaml:"runner,omitempty"`
    Options map[string]interface{} `yaml:"options,omitempty"`
    Supported string `yaml:"supported,omitempty"`
}
1 голос
/ 20 марта 2019

Я не уверен, что маршалинг в типа interface{} будет работать. Маршалеры полагаются на рефлексию, чтобы знать, куда поместить данные, поэтому им нужно конкретное значение типа, чтобы знать, как хранить каждое поле / элемент.

Если у вас сложная конфигурация YAML, вы можете вставить ее в онлайн-генератор YAML-to-go , чтобы получить совместимое определение типа:

type AutoGenerated struct {
    Version       string `yaml:"version"`
    RunParameters struct {
        Before []struct {
            Runner  string `yaml:"runner"`
            Options struct {
                Cmd []string `yaml:"cmd"`
            } `yaml:"options"`
            Supported string `yaml:"supported"`
        } `yaml:"before"`
        After []struct {
            Runner  string `yaml:"runner"`
            Options struct {
                Cmd []string `yaml:"cmd"`
            } `yaml:"options"`
            Supported string `yaml:"supported"`
        } `yaml:"after"`
    } `yaml:"run-parameters"`
}

Рекомендуется извлекать подтипы и определять их явно - для повторного использования.

Наконец, если поле является необязательным, измените его на указатель - предостережение заключается в том, что вам придется проверять nil при доступе к любым подполям, чтобы избежать паники во время выполнения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...