Saturday, March 26, 2016

Encode Decode arbitrary map and JSON in Go golang

Encode Decode arbitrary map and JSON in Go golang

package main

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

func main() {
    /*
     * Encode Decode arbitrary map and JSON
     */
    orderMap := map[string]interface{}{
      "status": true,
      "name": "bot",
      "age": 18,
      //"itemArr": []map[string]interface{}{},
      "itemArr": []interface{}{},
    }

    orderMap["email"] = "bot@example.com"

    item0 := map[string]interface{}{
      "lineNum": 0,
      "itemNum": "A0",
      "itemPrice": 90,
    }
    item1 := map[string]interface{}{
      "lineNum": 1,
      "itemNum": "A1",
      "itemPrice": 91,
      "accessoryArr": []interface{}{},
    }

    item1["accessoryArr"] = append(item1["accessoryArr"].([]interface{}), map[string]interface{}{"name": "bag", "price": 10})
    item1["accessoryArr"] = append(item1["accessoryArr"].([]interface{}), map[string]interface{}{"name": "tray", "price": 12})

    // To access the element we can use a type assertion to access the underlying map of the orderMap["itemArr"].
    orderMap["itemArr"] = append(orderMap["itemArr"].([]interface{}), item0)
    orderMap["itemArr"] = append(orderMap["itemArr"].([]interface{}), item1)

    orderJson, err := json.Marshal(orderMap)

    if err == nil {
      itemArrType := reflect.TypeOf(orderMap["itemArr"])
      itemArrTypeKind := reflect.TypeOf(orderMap["itemArr"]).Kind()
      itemArrElemType := reflect.TypeOf(orderMap["itemArr"]).Elem()

      fmt.Printf("itemArr: %v\n", itemArrType)
      fmt.Printf("itemArrTypeKind: %v\n", itemArrTypeKind)
      fmt.Printf("itemElement: %v\n", itemArrElemType)
      fmt.Printf("\n")

      fmt.Println("=== Showing the original orderMap:")

      fmt.Printf("%v\n\n", orderMap)

      fmt.Println("=== Showing the encoded orderJson:")

      fmt.Printf("%v\n\n", string(orderJson))

      fmt.Println("=== Showing the decoded orderJson:")

      // As we're un-marshalling into an interface, we need to inform go what data type each key is before we can perform operations on it.
      // This is what the .(map[string]interface{}) does
      var orderMapTmp map[string]interface{}
      json.Unmarshal([]byte(orderJson), &orderMapTmp)
      fmt.Printf("%v\n\n", orderMapTmp)

      fmt.Println("=== Showing how to access individual element in the decoded orderJson:")

      // The data type here was the key. [0] was not actually a map, but an interface{}, which could be anything - a map, a string, an int. You need to "type assertion" it to a map first, or do the awkward case switch outlined in JSON and Go.
      // Otherwise, you will get "invalid operation: type interface {} does not support indexing)".
      fmt.Printf("itemNum: %v\n", orderMapTmp["itemArr"].([]interface{})[0].(map[string]interface{})["itemNum"])
      fmt.Printf("itemPrice: %v\n", orderMapTmp["itemArr"].([]interface{})[0].(map[string]interface{})["itemPrice"])
    }
}

Output:

itemArr: []interface {}
itemArrTypeKind: slice
itemElement: interface {}

=== Showing the original orderMap:
map[status:true name:bot age:18 itemArr:[map[lineNum:0 itemNum:A0 itemPrice:90] map[itemPrice:91 accessoryArr:[map[name:bag price:10] map[price:12 name:tray]] lineNum:1 itemNum:A1]] email:bot@example.com]

=== Showing the encoded orderJson:
{"age":18,"email":"bot@example.com","itemArr":[{"itemNum":"A0","itemPrice":90,"lineNum":0},{"accessoryArr":[{"name":"bag","price":10},{"name":"tray","price":12}],"itemNum":"A1","itemPrice":91,"lineNum":1}],"name":"bot","status":true}

=== Showing the decoded orderJson:
map[status:true age:18 email:bot@example.com itemArr:[map[itemNum:A0 itemPrice:90 lineNum:0] map[accessoryArr:[map[name:bag price:10] map[name:tray price:12]] itemNum:A1 itemPrice:91 lineNum:1]] name:bot]

=== Showing how to access individual element in the decoded orderJson:
itemNum: A0
itemPrice: 90

Reference:

https://michaelheap.com/golang-encodedecode-arbitrary-json/

http://stackoverflow.com/questions/25214036/getting-invalid-operation-mymaptitle-type-interface-does-not-support-in

No comments: