2017-08-25 106 views
0

我有一些处理YAML配置文件的代码,这个文件有点失控w/type断言,我觉得必须有更好的方法来做到这一点。在Go中解析动态YAML的习惯用法是什么?

下面是我的配置文件中的相关片段:

plugins: 
    taxii20: 
    default: default 
    api_roots: 
     default: 
     auth: 
      - ldap 
      - mutualtls 
     collections: 
      all: 
      selector: g.V().Save("<type>").Save("<created>").All() 
      selector_query_lang: gizmo 

这是我的解析代码:

func parseTaxiiConfig() { 
    plg.ConfigMutex.Lock() 
    taxiiConfig := plg.ConfigData.Plugins["taxii20"].(map[interface{}]interface{}) 
    ConfigData = &Config{} 
    if taxiiConfig["default"] != nil { 
     ConfigData.DefaultRoot = taxiiConfig["default"].(string) 
    } 
    if taxiiConfig["api_roots"] != nil { 
     ConfigData.APIRoots = make([]model.APIRoot, 0) 
     iroots := taxiiConfig["api_roots"].(map[interface{}]interface{}) 
     for iname, iroot := range iroots { 
      root := model.APIRoot{Name: iname.(string)} 
      authMethods := iroot.(map[interface{}]interface{})["auth"].([]interface{}) 
      root.AuthMethods = make([]string, 0) 
      for _, method := range authMethods { 
       root.AuthMethods = append(root.AuthMethods, method.(string)) 
      } 
      collections := iroot.(map[interface{}]interface{})["collections"].(map[interface{}]interface{}) 
      root.Collections = make([]model.Collection, 0) 
      for icolName, icollection := range collections { 
       collection := model.Collection{Name: icolName.(string)} 
       collection.Selector = icollection.(map[interface{}]interface{})["selector"].(string) 
       collection.SelectorQueryLang = icollection.(map[interface{}]interface{})["selector_query_lang"].(string) 
       root.Collections = append(root.Collections, collection) 
      } 
      ConfigData.APIRoots = append(ConfigData.APIRoots, root) 
     } 
    } 
    plg.ConfigMutex.Unlock() 

    // debug 
    fmt.Println(ConfigData) 
} 

的代码按预期工作,但在这里只是这么多类型的断言和我可以不会动摇我错过了更好的方式的感觉。

作为配置暗示的一个可能的关键项目,这是配置Caddy风格的插件系统,所以主配置分析器不能提前知道插件配置的外观形状。它必须将配置文件的插件部分的处理委托给插件本身。

+0

实际上,发现我的一些同事的代码,真实解决这个问题http://github.com/mitchellh/mapstructure - 稍后我会更新这个问题,如果我能得到那个工作。 –

回答

0

这是我想出来的。更可读。

// Config represents TAXII 2.0 plugin structure 
type Config struct { 
    DefaultRoot string 
    APIRoots []model.APIRoot 
} 

// Intermediate config for mapstructure 
type configRaw struct { 
    DefaultRoot string    `mapstructure:"default"` 
    APIRoots map[string]apiRootRaw `mapstructure:"api_roots"` 
} 
type apiRootRaw struct { 
    AuthMethods []string     `mapstructure:"auth"` 
    Collections map[string]collectionRaw `mapstructure:"collections"` 
} 
type collectionRaw struct { 
    Selector   string `mapstructure:"selector"` 
    SelectorQueryLang string `mapstructure:"selector_query_lang"` 
} 

func parseTaxiiConfig() error { 
    plg.ConfigMutex.Lock() 
    defer plg.ConfigMutex.Unlock() 

    taxiiConfig := plg.ConfigData.Plugins["taxii20"].(map[interface{}]interface{}) 
    fmt.Println(taxiiConfig) 
    ConfigData = &Config{} 
    raw := &configRaw{} 
    err := mapstructure.Decode(taxiiConfig, raw) 
    if err != nil { 
     return err 
    } 

    ConfigData.DefaultRoot = raw.DefaultRoot 
    ConfigData.APIRoots = make([]model.APIRoot, 0) 
    for name, root := range raw.APIRoots { 
     apiRoot := model.APIRoot{Name: name} 
     apiRoot.AuthMethods = root.AuthMethods 
     apiRoot.Collections = make([]model.Collection, 0) 
     for colName, col := range root.Collections { 
      collection := model.Collection{Name: colName} 
      collection.Selector = col.Selector 
      collection.SelectorQueryLang = col.SelectorQueryLang 
      apiRoot.Collections = append(apiRoot.Collections, collection) 
     } 
     ConfigData.APIRoots = append(ConfigData.APIRoots, apiRoot) 
    } 

    return nil 
} 
相关问题