Whats the best way to get content from a generic and somehow dynamic go map?

你。 提交于 2021-02-04 21:57:49

问题


I have this json that I convert to:

var leerCHAT []interface{}

but I am going through crazy hoops to get to any point on that map inside map and inside map crazyness, specially because some results are different content. this is the Json

[
   null,
   null,
   "hub:zWXroom",
   "presence_diff",
   {
      "joins":{
         "f718a187-6e96-4d62-9c2d-67aedea00000":{
            "metas":[
               {
                  "context":{},
                  "permissions":{},
                  "phx_ref":"zNDwmfsome=",
                  "phx_ref_prev":"zDMbRTmsome=",
                  "presence":"lobby",
                  "profile":{},
                  "roles":{}
               }
            ]
         }
      },
      "leaves":{}
   }
]

I need to get to profile then inside there is a "DisplayName" field.

so I been doing crazy hacks.. and even like this I got stuck half way...

First is an array so I can just do something[elementnumber] then is when the tricky mapping starts... SORRY about all the prints etc is to debug and see the number of elements I am getting back.

if leerCHAT[3] == "presence_diff" {
                var id string
                presence := leerCHAT[4].(map[string]interface{})
                log.Printf("algo: %v", len(presence))
                log.Printf("algo: %s", presence["joins"])
                vamos := presence["joins"].(map[string]interface{})
                for i := range vamos {
                    log.Println(i)
                    id = i
                }
                log.Println(len(vamos))

                vamonos := vamos[id].(map[string]interface{})
                log.Println(vamonos)
                log.Println(len(vamonos))

                metas := vamonos["profile"].(map[string]interface{})   \\\ I get error here..

                log.Println(len(metas))
            }

so far I can see all the way to the meta:{...} but can't continue with my hacky code into what I need.

NOTICE: that since the id after Joins: and before metas: is dynamic I have to get it somehow since is always just one element I did the for range loop to grab it.


回答1:


The array element at index 3 describes the type of the variant JSON at index 4.

Here's how to decode the JSON to Go values. First, declare Go types for each of the variant parts of the JSON:

type PrescenceDiff struct {
     Joins map[string]*Presence // declaration of Presence type to be supplied
     Leaves map[string]*Presence
}

type Message struct {
     Body string
}

Declare a map associating the type string to the Go type:

var messageTypes = map[string]reflect.Type{
    "presence_diff": reflect.TypeOf(&PresenceDiff{}),
    "message":       reflect.TypeOf(&Message{}),
    // add more types here as needed
}

Decode the variant part to a raw message. Use use the name in the element at index 3 to create a value of the appropriate Go type and decode to that value:

func decode(data []byte) (interface{}, error) {
    var messageType string
    var raw json.RawMessage
    v := []interface{}{nil, nil, nil, &messageType, &raw}
    err := json.Unmarshal(data, &v)
    if err != nil {
        return nil, err
    }

    if len(raw) == 0 {
        return nil, errors.New("no message")
    }

    t := messageTypes[messageType]
    if t == nil {
        return nil, fmt.Errorf("unknown message type: %q", messageType)
    }

    result := reflect.New(t.Elem()).Interface()
    err = json.Unmarshal(raw, result)
    return result, err
}

Use type switches to access the variant part of the message:

defer ws.Close()

for {
    _, data, err := ws.ReadMessage()
    if err != nil {
        log.Printf("Read error: %v", err)
        break
    }

    v, err := decode(data)
    if err != nil {
        log.Printf("Decode error: %v", err)
        continue
    }

    switch v := v.(type) {
    case *PresenceDiff:
        fmt.Println(v.Joins, v.Leaves)
    case *Message:
        fmt.Println(v.Body)
    default:
        fmt.Printf("type %T not handled\n", v)
    }
}

Run it on the playground.



来源:https://stackoverflow.com/questions/62698268/whats-the-best-way-to-get-content-from-a-generic-and-somehow-dynamic-go-map

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!