golang 解析json问题

{
    "method": "update",
    "params": ["TODOS", [{
        "id": 275570305,
        "time": 1598273441.8892069,
        "type": "myid"
    }]]
}

该段json使用golang解析失败, golang代码:


    var mapTick struct {
        Method string        `json:"method"`
        Params []interface{} `json:"params"`
    }
    type Param []struct {
        ID     int64   `json:"id"`
        Time   float64 `json:"time"`
        Type   string  `json:"type"`
    }

    err := json.Unmarshal([]byte(jsonstr), &mapTick)
    if err != nil {
        fmt.Println(err)
    } else {
        if len(mapTick.Params) == 2 {
            fmt.Println(mapTick.Params[1])
            if _ , ok := mapTick.Params[1].(Param); ok {
                res := mapTick.Params[1].(Param)
                fmt.Println(res)
            }
        }
    }

除了我这种代码, 还有更好的解析方法吗?

阅读 2.2k
2 个回答
if _ , ok := mapTick.Params[1].(Param); ok {

这个地方不对,可以用reflect.Typeof(mapTick.Params[1])来查看其类型,其实并不是Param

另外定义结构体的时候,最好不要定义为数组:type Param []struct {
可读性太差,自己也容易记错

我改写了下,可以参考:

package main

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

type Param struct {
    ID   int64   `json:"id"`
    Time float64 `json:"time"`
    Type string  `json:"type"`
}

type Tick struct {
    Method string
    Params struct {
        Todo string
        Arr  []Param
    }
}

func (t *Tick) UnmarshalJSON(data []byte) error {
    mapTick := struct {
        Method string        `json:"method"`
        Params []interface{} `json:"params"`
    }{}

    err := json.Unmarshal(data, &mapTick)
    if err != nil {
        return err
    }

    t.Method = mapTick.Method

    if len(mapTick.Params) == 2 {
        for _, tick := range mapTick.Params {
            if _, ok := tick.(string); ok {
                t.Params.Todo = tick.(string)
            }

            if ps, ok := tick.([]interface{}); ok {
                for _, p := range ps {
                    if _, ok := p.(map[string]interface{}); ok {
                        param := Param{}
                        kv := p.(map[string]interface{})
                        param.ID = (int64)(kv["id"].(float64))
                        param.Time = kv["time"].(float64)
                        param.Type = kv["type"].(string)
                        t.Params.Arr = append(t.Params.Arr, param)
                    } else {
                        return errors.New("Tick UnmarshalJSON failed.")
                    }
                }
            }
        }
    }

    return nil
}

func main() {
    jsonstr := `{
        "method": "update",
        "params": ["TODOS", [{
        "id": 275570305,
        "time": 1598273441.8892069,
        "type": "myid"
        }]]
        }`

    myTick := Tick{}
    err := json.Unmarshal([]byte(jsonstr), &myTick)
    if err != nil {
        fmt.Println(err)
        return
    }

    fmt.Println(myTick)
}

输出如下:
{update {TODOS [{275570305 1.598273441889207e+09 myid}]}}

Tick的结构需要根据实际情况定义,这里是我根据你现有json定义的,可以自行修改。

特殊json结构可以定义自己的特殊结构体来解析这段json,并且实现 json.MarshalJSONjson.UnMarshalJSON 接口就行了。

直接上代码:

package main

import (
    "encoding/json"
    "errors"
    "fmt"
    "log"
)

type mapTick struct {
    Method string          `json:"method"`
    Params *ObjectOrString `json:"params"`
}

type ObjectItem struct {
    ID   int64   `json:"id"`
    Time float64 `json:"time"`
    Type string  `json:"type"`
}

type ObjectOrString struct {
    obj []*ObjectItem
    str string
}

func (s *ObjectOrString) UnmarshalJSON(b []byte) error {
    var x []interface{}
    err := json.Unmarshal(b, &x)
    if err != nil {
        return err
    }
    if len(x) != 2 {
        return errors.New("invalid json")
    }
    for _, val := range x {
        switch v := val.(type) {
        case string:
            s.str = v
        case []interface{}:
            s.obj = make([]*ObjectItem, 0)
            data, err := json.Marshal(v)
            if err != nil {
                return err
            }
            err = json.Unmarshal(data, &s.obj)
            if err != nil {
                return err
            }
        }
    }

    return nil
}

func (s *ObjectOrString) MarshalJSON() ([]byte, error) {
    var data = make([]interface{}, 0)
    data = append(data, s.str)
    data = append(data, s.obj)
    return json.Marshal(data)
}

const jsonString = `{
    "method": "update",
    "params": ["TODOS", [{
        "id": 275570305,
        "time": 1598273441.8892069,
        "type": "myid"
    }]]
}`

func main() {
    var mt = new(mapTick)
    err := json.Unmarshal([]byte(jsonString), mt)
    if err != nil {
        log.Println(err)
        return
    }

    fmt.Println(mt.Params.str, mt.Params.obj, mt.Params.obj[0])

    data, err := json.MarshalIndent(mt, "", "\t")
    if err != nil {
        log.Println(err)
        return
    }

    fmt.Println(string(data))
}

输出:

TODOS [0xc0000a6260] &{275570305 1.598273441889207e+09 myid}
{
        "method": "update",
        "params": [
                "TODOS",
                [
                        {
                                "id": 275570305,
                                "time": 1598273441.889207,
                                "type": "myid"
                        }
                ]
        ]
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题