2015-08-21 9 views
5

Ich versuche, eine yaml Akte mit gehen zu analysieren. Das Problem besteht darin, dass die Schlüssel in der Yaml-Datei möglicherweise nicht immer identisch sind. Dies dient der API-Versionierung, damit der Benutzer die unterstützten Versionen definieren kann. Zum Beispiel V1, V2, V3 usw. Sie brauchen nicht, um zu sein und Versionen weglassen können sie nicht unterstützen IE V0, V2, V5 usw.Wie man yaml mit dyanmic Schlüssel in Golang parse

package main 

import (
    "fmt" 
    "gopkg.in/yaml.v2" 
) 

var data = ` 
--- 
development: 
    skip-header-validation: true 
    V1: 
    current: "1.0.0" 
    mime_types: 
     - application/vnd.company.jk.identity+json; 
     - application/vnd.company.jk.user+json; 
     - application/vnd.company.jk.role+json; 
     - application/vnd.company.jk.scope+json; 
     - application/vnd.company.jk.test+json; 
    skip-mime-type-validation: true 
    skip-version-validation: true 
    V2: 
    current: "2.0.0" 
    mime_types: 
     - application/vnd.company.jk.identity+json; 
     - application/vnd.company.jk.user+json; 
     - application/vnd.company.jk.role+json; 
     - application/vnd.company.jk.scope+json; 
     - application/vnd.company.jk.test+json; 

` 

type MajorVersion struct { 
    Current     string `yaml:"current"` 
    MimeTypes    []string `yaml:"mime_types"` 
    SkipVersionValidation bool  `yaml:"skip-version-validation"` 
    SkipMimeTypeValidation bool  `yaml:"skip-mime-type-validation"` 
} 

type Environment struct { 
    SkipHeaderValidation bool  `yaml:"skip-header-validation"` 
    Version    map[string]MajorVersion 
} 

func main() { 
    e := Environment{} 

    yaml.Unmarshal([]byte(data), &e) 
    fmt.Println(e) 
} 

ich eine ähnliche Frage hier sah, fragte Golang parse a json with DYNAMIC key Dies ist auf der obersten Ebene und hat nicht ganz herausgefunden, wie dies von innerhalb der Struktur zu tun ist.

Antwort

7

Zuerst versuchen Sie, den Stamm als Environment zu analysieren, aber sein tatsächlicher Typ ist map[string]Environment. Zweitens benötigen Sie eine benutzerdefinierte Unmarshaler, wenn Sie diese Typstruktur beibehalten möchten. Etwas wie folgt aus:

package main 

import (
    "fmt" 

    "gopkg.in/yaml.v2" 
) 

var data = ` 
--- 
development: 
    skip-header-validation: true 
    V1: 
    current: "1.0.0" 
    mime_types: 
     - application/vnd.company.jk.identity+json; 
     - application/vnd.company.jk.user+json; 
     - application/vnd.company.jk.role+json; 
     - application/vnd.company.jk.scope+json; 
     - application/vnd.company.jk.test+json; 
    skip-mime-type-validation: true 
    skip-version-validation: true 
    V2: 
    current: "2.0.0" 
    mime_types: 
     - application/vnd.company.jk.identity+json; 
     - application/vnd.company.jk.user+json; 
     - application/vnd.company.jk.role+json; 
     - application/vnd.company.jk.scope+json; 
     - application/vnd.company.jk.test+json; 

` 

type MajorVersion struct { 
    Current    string `yaml:"current"` 
    MimeTypes    []string `yaml:"mime_types"` 
    SkipVersionValidation bool  `yaml:"skip-version-validation"` 
    SkipMimeTypeValidation bool  `yaml:"skip-mime-type-validation"` 
} 

type Environment struct { 
    SkipHeaderValidation bool 
    Versions    map[string]MajorVersion 
} 

func (e *Environment) UnmarshalYAML(unmarshal func(interface{}) error) error { 
    var params struct { 
     SkipHeaderValidation bool `yaml:"skip-header-validation"` 
    } 
    if err := unmarshal(&params); err != nil { 
     return err 
    } 
    var versions map[string]MajorVersion 
    if err := unmarshal(&versions); err != nil { 
     // Here we expect an error because a boolean cannot be converted to a 
     // a MajorVersion 
     if _, ok := err.(*yaml.TypeError); !ok { 
      return err 
     } 
    } 
    e.SkipHeaderValidation = params.SkipHeaderValidation 
    e.Versions = versions 
    return nil 
} 

func main() { 
    var e map[string]Environment 
    if err := yaml.Unmarshal([]byte(data), &e); err != nil { 
     fmt.Println(err.Error()) 
    } 
    fmt.Printf("%#v\n", e) 
} 

Ausgang (nach makeup verwenden):

map[string]main.Environment{ 
    "development": { 
     SkipHeaderValidation: true, 
     Versions:    { 
      "V2": { 
       Current:    "2.0.0", 
       MimeTypes:    {"application/vnd.company.jk.identity+json;", "application/vnd.company.jk.user+json;", "application/vnd.company.jk.role+json;", "application/vnd.company.jk.scope+json;", "application/vnd.company.jk.test+json;"}, 
       SkipVersionValidation: false, 
       SkipMimeTypeValidation: false, 
      }, 
      "V1": { 
       Current:    "1.0.0", 
       MimeTypes:    {"application/vnd.company.jk.identity+json;", "application/vnd.company.jk.user+json;", "application/vnd.company.jk.role+json;", "application/vnd.company.jk.scope+json;", "application/vnd.company.jk.test+json;"}, 
       SkipVersionValidation: true, 
       SkipMimeTypeValidation: true, 
      }, 
     }, 
    }, 
} 
+0

Wow sehr netter Mann, thnx. Sehr cool zu sehen, wie das gemacht wird. Es ist lustig, wie viel Code man manchmal braucht, um Yam zu parsen! – earlonrails