2016-07-11 9 views
3

私はYamlファイルにアクセスして個々の値を取得しようとしていますが、これを達成するためにStruct構文で苦労しています。下のコードはYamlを処理し、Struct全体を印刷することができますが、個々のecs.services.name属性にはどのようにアクセスできますか?Golangネストされたヤムの値

私はいくつかのYamlライブラリに出くわしましたが、完全に動作させることはできませんでしたので、これをどう対処するかに関するお勧めは歓迎します。

test.yaml:

ecs: 
    services: 
    - name: my-service 
     taskDefinition: my-task-def 
     desiredCount: 1 

Yaml.go

package main 

import (
    "fmt" 
    "io/ioutil" 
    "path/filepath" 

    "gopkg.in/yaml.v2" 
) 

type Config struct { 
    //Ecs []map[string]string this works for ecs with name 
    Ecs struct { 
     Services []struct { 
      Name   string 
      TaskDefinition string 
      DesiredCount int 
     } 
    } 
    //Services []map[string][]string 
} 

func main() { 
    filename, _ := filepath.Abs("test.yaml") 

    yamlFile, err := ioutil.ReadFile(filename) 
    check(err) 

    var config Config 

    err = yaml.Unmarshal(yamlFile, &config) 
    check(err) 

    fmt.Printf("Description: %#v\n", config.Ecs.Services) 
} 

func check(e error) { 
    if e != nil { 
     panic(e) 
    } 
} 

出力

$ go run yaml.go 
Description: []struct { Name string; TaskDefinition string; DesiredCount int }{struct { Name string; TaskDefinition string; DesiredCount int }{Name:"my-service", TaskDefinition:"", DesiredCount:0}} 

答えて

1

私はあなたが余分なレベルを持っていると思います入れ子のConfig構造体は必須ではありません。以下の定義を試してみてください:

type Ecs struct { 
    Services []Service 
} 

type Service struct { 
    Name   string 
    TaskDefinition string 
    DesiredCount int 
} 

そして、yamlデータを非整列化しようとしてください。おそらくecs.Servicesとしてデータにアクセスすることができます。

0

フィールドには小文字を使用するので、structタグを使用する必要があります。これは異なる名前のフィールドにも適用されます。

これを修正する方法の例を参照してください。https://play.golang.org/p/WMmlQsqYeBもう1つの回答が間違っています。

1

yamlファイルでネストされた検索を実行する必要があったのと同様の要件がありました。私が箱の解決策を見つけなかったので、私はそれを自分で書く必要がありました。

私はまたしたくなかった私は、この構造体からネストされた値にアクセスし、印刷したいと出力のような

--- yaml->a: Easy! 
--- yaml->b->c: 2 
--- yaml->b->x: None //not existing in the yaml 
--- yaml->y->w: None //not existing in the yaml 
--- yaml->b->d[0]: 3 //accessing value from a list 
--- yaml->e->f->g: hi 

以下でなければならない

"a": "Easy!" 
"b": 
    "c": "2" 
    "d": ["3", "4"] 
"e": 
    "f": {"g":"hi","h":"6"} 

以下のような内容を持つYAMLファイルを持っています解析されたyamlを保持する構造体を定義します。 golangの最も一般的な構造はinterface {}です。 yamlをアンマーシャリングするのに最適な構造はmap[interface{}]interface{}です。 Javaから来る人々の場合、これはMap<Object,Object>に似ています。データがアンマーシャリングされると、ネストされたキーを使用して構造体を走査し、値を返す関数を記述する必要がありました。

以下はそのコードです。コメントをオンにして、コードがネストされた構造をどのようにトラバースし、最後に値を取得するかを知るために実行します。この例では、yamlのすべての値が文字列であると仮定していますが、これは数値のキーと値に対しても拡張できます。

package main 

import (
    "fmt" 
    "gopkg.in/yaml.v2" 
    "io/ioutil" 
    "reflect" 
) 

func main() { 

    testFile := "test.yaml" 
    testYaml, rerr := ioutil.ReadFile(testFile) 
    if rerr != nil { 
     fmt.Errorf("error reading yaml file: %v", rerr) 
    } 

    m := make(map[interface{}]interface{}) 
    if uerr := yaml.Unmarshal([]byte(testYaml), &m); uerr != nil { 
     fmt.Errorf("error parsing yaml file: %v", uerr) 
    } 

    fmt.Printf("--- yaml->a: %v\n\n", getValue(m, []string{"a"}, -1))   //single value in a map 
    fmt.Printf("--- yaml->b->c: %v\n\n", getValue(m, []string{"b", "c"}, -1)) //single value in a nested map 
    fmt.Printf("--- yaml->b->x: %v\n\n", getValue(m, []string{"b", "x"}, -1)) //value for a non existent nest key 
    fmt.Printf("--- yaml->y->w: %v\n\n", getValue(m, []string{"y", "w"}, -1)) //value for a non existent nest key 
    fmt.Printf("--- yaml->b->d[0]: %v\n\n", getValue(m, []string{"b", "d"}, 0)) 
    fmt.Printf("--- yaml->e->f->g: %v\n\n", getValue(m, []string{"e", "f", "g"}, -1)) 
} 

func getValue(obj map[interface{}]interface{}, keys []string, indexOfElementInArray int) string { 

    //fmt.Printf("--- Root object:\n%v\n\n", obj) 
    value := "None" 
    queryObj := obj 
    for i := range keys { 
     if queryObj == nil { 
      break 
     } 
     if i == len(keys)-1 { 
      break 
     } 
     key := keys[i] 
     //fmt.Printf("--- querying for sub object keyed by %v\n", key) 
     if queryObj[key] != nil { 
      queryObj = queryObj[key].(map[interface{}]interface{}) 
      //fmt.Printf("--- Sub object keyed by %v :\n%v\n\n", key, queryObj) 
     } else { 
      //fmt.Printf("--- No sub object keyed by %v :\n%v\n\n", key) 
      break 
     } 
    } 
    if queryObj != nil { 
     lastKey := keys[len(keys)-1] 
     //fmt.Printf("--- querying for value keyed by %v\n", lastKey) 

     if queryObj[lastKey] != nil { 
      objType := reflect.TypeOf(queryObj[lastKey]) 
      //fmt.Printf("Type of value %v\n", objType) 
      if objType.String() == "[]interface {}" { 
       //fmt.Printf("Object is a array %v\n", objType) 
       tempArr := queryObj[lastKey].([]interface{}) 
       //fmt.Printf("Length of array is %v\n", len(tempArr)) 
       if indexOfElementInArray >= 0 && indexOfElementInArray < len(tempArr) { 
        value = queryObj[lastKey].([]interface{})[indexOfElementInArray].(string) 
       } 
      } else { 
       value = queryObj[lastKey].(string) 
      } 
     } 
    } 

    return value 
} 
関連する問題