登录
首页 >  Golang >  Go问答

常见的 JSON 数组 -> mapjson.RawMessage

来源:stackoverflow

时间:2024-02-29 09:12:24 406浏览 收藏

从现在开始,努力学习吧!本文《常见的 JSON 数组 -> mapjson.RawMessage》主要讲解了等等相关知识点,我会在golang学习网中持续更新相关的系列文章,欢迎大家关注并积极留言建议。下面就先一起来看一下本篇正文内容吧,希望能帮到你!

问题内容

我正在尝试解组 http rest api 请求的结果,该请求根据结果数量返回一个对象或对象数组

请求是通用的,因为我试图围绕特定的 rest api 构建一个包装器,其调用方式如下:

// function prototype where i am trying to convert the response
func (client *client) get(endpoint string, data map[string]string) (map[string]json.rawmessage, error)

// the way the function is called
client.get("/v1/users", map[string]string{"filter.abc": "lorem ipsum"})

两个响应示例:

[
  {
    "abc": "def",
    "efg": 123
    "hij": [
      {
        "klm": "nop"
      }
    ]
  },
  {
    "abc": "def",
    "efg": 123
    "hij": [
      {
        "klm": "nop"
      }
    ]
  }
]
// response 1: array of json objects that have child arrays

{
  "abc": "def",
  "efg": 123
  "hij": [
    {
      "klm": "nop"
    }
  ]
}
// response 2: in this case, only one element was returned.

我已经实现了仅对响应 2 执行此操作,如下所示:

// [...]
byteBody = ioutil.ReadAll(res.Body)
// [...]
var body map[string]json.RawMessage
if err := json.Unmarshal(byteBody, &body); err != nil { [...] }

那么,解析这个最惯用的方法是什么?有什么方法可以避免编写冗余代码并解析这两个响应吗?我正在考虑将响应放入的“模型”作为附加参数。这是一个好的做法吗?提前非常感谢您!


正确答案


不确定是否惯用,但此代码可能是 example

简而言之,您可以尝试以一种格式解组,如果失败,则以另一种格式解组

关键功能是

func parsestr(data string) ([]item, error) {
    item := item{}
    if err := json.unmarshal([]byte(data), &item); err == nil {
        return []item{item}, nil
    }

    items := []item{}
    if err := json.unmarshal([]byte(data), &items); err != nil {
        return nil, errors.new("invalid json data")
    }
    return items, nil

}

检查 json 文档中的第一个非空白字节以确定该文档是数组还是对象。

func decodearrayorobject(doc []byte) ([]map[string]json.rawmessage, error) {
    trimmeddoc := bytes.trimspace(doc)
    switch {
    case len(trimmeddoc) == 0:
        return nil, errors.new("empty body")
    case trimmeddoc[0] == '{':
        var m map[string]json.rawmessage
        err := json.unmarshal(doc, &m)
        return []map[string]json.rawmessage{m}, err
    case trimmeddoc[0] == '[':
        var s []map[string]json.rawmessage
        err := json.unmarshal(doc, &s)
        return s, err
    default:
        return nil, errors.new("unexpected type")
    }
}

使用 reflect 包创建一个适用于任意切片类型的函数:

func decodearrayorobject(doc []byte, slicep interface{}) error {
    trimmeddoc := bytes.trimspace(doc)
    switch {
    case len(trimmeddoc) == 0:
        return errors.new("empty document")
    case trimmeddoc[0] == '[':
        return json.unmarshal(doc, slicep)
    case trimmeddoc[0] == '{':
        s := reflect.valueof(slicep).elem()
        s.set(reflect.makeslice(s.type(), 1, 1))
        return json.unmarshal(doc, s.index(0).addr().interface())
    default:
        return errors.new("unexpected type")
    }
}

使用指向结构体切片的指针或指向结构体指针切片的指针来调用该函数。

var v []Example
err := decodeArrayOrObject(body, &v)

Run an example on the playground

今天关于《常见的 JSON 数组 -> mapjson.RawMessage》的内容介绍就到此结束,如果有什么疑问或者建议,可以在golang学习网公众号下多多回复交流;文中若有不正之处,也希望回复留言以告知!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>