2015-08-21 12 views
5

Sto cercando di analizzare un file yaml con go. Il problema è che le chiavi nel file yaml potrebbero non essere sempre le stesse. Questo è per fare il versioning delle API in modo che l'utente possa definire le versioni che supportano. Per esempio V1, V2, V3 ecc Essi non hanno bisogno di essere in ordine e possono omettere le versioni non supportano IE V0, V2, V5 eccCome analizzare yaml con la chiave dyanmic in Golang

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) 
} 

ho visto una domanda simile chiesto qui Golang parse a json with DYNAMIC key Questo è al livello più alto e non ho ancora capito come farlo all'interno della struttura.

risposta

7

In primo luogo, si sta tentando di analizzare la radice come Environment, ma il suo tipo effettivo è map[string]Environment. Secondo, avrai bisogno di un custom Unmarshaler se vuoi mantenere quella struttura di tipo. Qualcosa di simile a questo:

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) 
} 

uscita (dopo aver usato makeup):

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 uomo molto bello, thnx. Molto bello vedere come è fatto in viaggio. È divertente la quantità di codice che ti serve a volte solo per analizzare yaml! – earlonrails

Problemi correlati