2015-03-31 22 views
5

考慮下面的代碼:環流式/迭代嵌套JSON在走郎

package main 

import (
"encoding/json" 
"fmt" 
"reflect" 
) 


func main() { 
    //Creating the maps for JSON 
    m := map[string]interface{}{} 

    //Parsing/Unmarshalling JSON encoding/json 
    err := json.Unmarshal([]byte(input), &m) 

    fmt.Println("\nReflect type of Parsing/Unmarshalling Error Object:\n",reflect.TypeOf(err)) 
    fmt.Println("\nParsing/Unmarshalling Error Object:\n",err) 
    if err != nil { 
     panic(err) 
    } 

    fmt.Println("\nParsed JSON is as follows:\n",m) 
    fmt.Println("\nReflect type of parsed json object:\n", reflect.TypeOf(m)) 

    for firstLvlkey, firstLvlValue := range m { 
     fmt.Println("First Level Key:", firstLvlkey) 
     fmt.Println("First Level Key reflect type of :", reflect.TypeOf(firstLvlkey)) 

     fmt.Println("First Level Value:", firstLvlValue) 
     fmt.Println("First Level Value reflect type of :", reflect.TypeOf(firstLvlValue)) 
     // <===============================> 
     //Here I want to iterate/loop over innerJSON1, InnerJSON2 then reach to level InnerInnerJSONArray - fld1 and fld2 
     // <===============================> 

    } 
} 

const input = ` 
{ 
    "outterJSON":{ 
     "innerJSON1":{ 
      "value1":10, 
      "value2":22 
      , 
      "InnerInnerArray": [ "test1" , "test2"], 
      "InnerInnerJSONArray": [ {"fld1" : "val1"} , {"fld2" : "val2"} ] 
      }, 
      "InnerJSON2":"NoneValue" 
     } 
    } 
    ` 

我有一些要求,像我想讀/讓所有的鍵和值在String類型進行一些處理ADN我無法定義struct,因爲我將獲得動態JSON輸入(例如InnerInnerArray作爲字符串,然後第二級循環將給出數組的索引並處理每個JSON具有密鑰fld1val1)。

我希望遍歷其中包含的每個鍵/值對,通過該映射的最有效方式是什麼?

注意:我是Go-lang的新手,您對問題的建議/改進也非常受歡迎。

回答

9

this博客條目它徹底講述了這個問題,特別是部分解碼任意數據。使用你可以做這樣的事情: (playground example

package main 

import (
    "encoding/json" 
    "fmt"  
) 

func main() { 
    // Creating the maps for JSON 
    m := map[string]interface{}{} 

    // Parsing/Unmarshalling JSON encoding/json 
    err := json.Unmarshal([]byte(input), &m) 

    if err != nil { 
     panic(err) 
    } 
    parseMap(m) 
} 

func parseMap(aMap map[string]interface{}) { 
    for key, val := range aMap { 
     switch concreteVal := val.(type) { 
     case map[string]interface{}: 
      fmt.Println(key) 
      parseMap(val.(map[string]interface{})) 
     case []interface{}: 
      fmt.Println(key) 
      parseArray(val.([]interface{})) 
     default: 
      fmt.Println(key, ":", concreteVal) 
     } 
    } 
} 

func parseArray(anArray []interface{}) { 
    for i, val := range anArray { 
     switch concreteVal := val.(type) { 
     case map[string]interface{}: 
      fmt.Println("Index:", i) 
      parseMap(val.(map[string]interface{})) 
     case []interface{}: 
      fmt.Println("Index:", i) 
      parseArray(val.([]interface{})) 
     default: 
      fmt.Println("Index", i, ":", concreteVal) 

     } 
    } 
} 

const input = ` 
{ 
    "outterJSON": { 
     "innerJSON1": { 
      "value1": 10, 
      "value2": 22, 
      "InnerInnerArray": [ "test1" , "test2"], 
      "InnerInnerJSONArray": [{"fld1" : "val1"} , {"fld2" : "val2"}] 
     }, 
     "InnerJSON2":"NoneValue" 
    } 
} 
` 

這將打印:

//outterJSON 
    //innerJSON1 
    //InnerInnerJSONArray 
    //Index: 0 
    //fld1 : val1 
    //Index: 1 
    //fld2 : val2 
    //value1 : 10 
    //value2 : 22 
    //InnerInnerArray 
    //Index 0 : test1 
    //Index 1 : test2 
    //InnerJSON2 : NoneValue 

關鍵的一點是,你必須使用類型斷言與接口類型時。類型開關可以根據需要輕鬆確定類型。代碼將遞歸地遍歷任何嵌套數組或地圖,以便您可以根據需要添加儘可能多的級別並獲取所有值。

1

您需要解析JSON,然後遍歷結構檢查包含值的類型並以某種方式處理它們。

下面的例子函數接受一個*interface{}(指針於任何類型的)和字符串,整數,和對象的指針的處理函數,它產生它發現的項目:

func eachJsonValue(obj *interface{}, handler func(*string, *int, *interface{})) { 
    if obj == nil { 
    return 
    } 
    // Yield all key/value pairs for objects. 
    o, isObject := (*obj).(map[string]interface{}) 
    if isObject { 
    for k, v := range o { 
     handler(&k, nil, &v) 
     eachJsonValue(&v, handler) 
    } 
    } 
    // Yield each index/value for arrays. 
    a, isArray := (*obj).([]interface{}) 
    if isArray { 
    for i, x := range a { 
     handler(nil, &i, &x) 
     eachJsonValue(&x, handler) 
    } 
    } 
    // Do nothing for primitives since the handler got them. 
} 

調用它,如下面所示將打印列出的結果。你的處理函數可以,當然,做一些特別的已知鍵/值,如「FLD1」:

func main() { 
    // Parse the JSON. 
    var obj interface{} 
    json.Unmarshal([]byte(input), &obj) // XXX: check the error value. 

    // Handle object key/value pairs and array index/items. 
    eachJsonValue(&obj, func(key *string, index *int, value *interface{}) { 
    if key != nil { // It's an object key/value pair... 
     fmt.Printf("OBJ: key=%q, value=%#v\n", *key, *value) 
    } else { // It's an array item... 
     fmt.Printf("ARR: index=%d, value=%#v\n", *index, *value) 
    } 
    }) 
} 

// OBJ: key="outterJSON", value=map[string]interface {}{...} 
// OBJ: key="innerJSON1", value=map[string]interface {}{...} 
// OBJ: key="value1", value=10 
// OBJ: key="value2", value=22 
// OBJ: key="InnerInnerArray", value=[]interface {}{...} 
// ARR: index=0, value="test1" 
// ARR: index=1, value="test2" 
// OBJ: key="InnerInnerJSONArray", value=[]interface {}{...} 
// ARR: index=0, value=map[string]interface {}{...} 
// OBJ: key="fld1", value="val1" 
// ARR: index=1, value=map[string]interface {}{...} 
// OBJ: key="fld2", value="val2" 
// OBJ: key="InnerJSON2", value="NoneValue" 
1

有相關的問題herehere(可能還有其他)。

還有一些更復雜的JSON解析API,使您的工作更輕鬆。一個例子是stretchr/objx

使用物objx的例子:

document, err := objx.FromJSON(json) 
// TODO handle err 
document.Get("path.to.field[0].you.want").Str() 

這工作,當你真的不知道該JSON結構將是什麼。但是,如果您事先知道JSON輸入的結構,首選方法是使用結構對其進行描述,並使用標準API進行編組。