如何在Golang中正确地解析没有键的JSON数组?

huangapple go评论119阅读模式
英文:

How to Unmarshall key-less JSON array in Golang correctly?

问题

我有一个看起来像这样的JSON数据:

[
{
"globalTradeID": 64201000,
"tradeID": 549285,
"date": "2016-11-11 23:51:58",
"type": "buy",
"rate": "10.33999779",
"amount": "0.02176472",
"total": "0.22504715"
},
{
"globalTradeID": 64200631,
"tradeID": 549284,
"date": "2016-11-11 23:48:39",
"type": "buy",
"rate": "10.33999822",
"amount": "0.18211700",
"total": "1.88308945"
}...
]

我尝试通过定义一个类型来解析这个JSON:

type TradeHistoryResponse []TradeHistoryInfo

type TradeHistoryInfo struct {
GlobalTradeID int64 json:"globalTradeID"
TradeID int64 json:"tradeID"
Date string json:"date"
Type string json:"type"
Rate float64 json:"rate,string"
Amount float64 json:"amount,string"
Total float64 json:"total,string"
}

然后按如下方式提取JSON数据:

//读取响应
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("[Poloniex] (doRequest) Failed to parse response for query to %s! (%s)", reqURL, err.Error())
}

//将JSON转换为结构体
var THR TradeHistoryResponse
err = json.Unmarshal(body, &THR)
if err != nil {
return nil, fmt.Errorf("[Poloniex] (doRequest) Failed to convert response into JSON for query to %s! (%s)", reqURL, err.Error())
}

我得到以下错误:

(json: cannot unmarshal object into Go value of type poloniex.TradeHistoryResponse)

我最好的猜测是Unmarshal无法工作的原因是数组没有键值?

希望能对如何解决这个问题有一些澄清。

英文:

I have JSON data which looks like this:

  1. [
  2. {
  3. "globalTradeID": 64201000,
  4. "tradeID": 549285,
  5. "date": "2016-11-11 23:51:58",
  6. "type": "buy",
  7. "rate": "10.33999779",
  8. "amount": "0.02176472",
  9. "total": "0.22504715"
  10. },
  11. {
  12. "globalTradeID": 64200631,
  13. "tradeID": 549284,
  14. "date": "2016-11-11 23:48:39",
  15. "type": "buy",
  16. "rate": "10.33999822",
  17. "amount": "0.18211700",
  18. "total": "1.88308945"
  19. }...
  20. ]

I've tried to unmarshall this JSON by defining a type:

  1. type TradeHistoryResponse []TradeHistoryInfo
  2. type TradeHistoryInfo struct {
  3. GlobalTradeID int64 `json:"globalTradeID"`
  4. TradeID int64 `json:"tradeID"`
  5. Date string `json:"date"`
  6. Type string `json:"type"`
  7. Rate float64 `json:"rate,string"`
  8. Amount float64 `json:"amount,string"`
  9. Total float64 `json:"total,string"`
  10. }

And then pulling the JSON data as so:

  1. //Read response
  2. body, err := ioutil.ReadAll(resp.Body)
  3. if err != nil {
  4. return nil, fmt.Errorf("[Poloniex] (doRequest) Failed to parse response for query to %s! (%s)", reqURL, err.Error())
  5. }
  6. //Convert JSON to struct
  7. var THR TradeHistoryResponse
  8. err = json.Unmarshal(body, &THR)
  9. if err != nil {
  10. return nil, fmt.Errorf("[Poloniex] (doRequest) Failed to convert response into JSON for query to %s! (%s)", reqURL, err.Error())
  11. }

I get the following error:

  1. (json: cannot unmarshal object into Go value of type poloniex.TradeHistoryResponse)

My best guess why the Unmarshall doesn't work is because the array is key-less?

Would love to have some clarification on the matter on how I might best get this working.

答案1

得分: 1

我没有认为在 JSON 中解组装一个数组是可以的,但是对于 encoding/json 的属性来说是可以的。以下是示例代码:

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "log"
  6. )
  7. var mjs string = "[" +
  8. "{\"globalTradeID\": 64201000," +
  9. "\"tradeID\": 549285," +
  10. "\"date\": \"2016-11-11 23:51:58\"," +
  11. "\"type\": \"buy\"," +
  12. "\"rate\": \"10.33999779\"," +
  13. "\"amount\": \"0.02176472\"," +
  14. "\"total\": \"0.22504715\"" +
  15. "}," +
  16. "{" +
  17. "\"globalTradeID\": 64200631," +
  18. "\"tradeID\": 549284," +
  19. "\"date\": \"2016-11-11 23:48:39\"," +
  20. "\"type\": \"buy\"," +
  21. "\"rate\": \"10.33999822\"," +
  22. "\"amount\": \"0.18211700\"," +
  23. "\"total\": \"1.88308945\"" +
  24. "}" +
  25. "]"
  26. type TradeHistoryResponse []TradeHistoryInfo
  27. type TradeHistoryInfo struct {
  28. GlobalTradeID int64 `json:"globalTradeID"`
  29. TradeID int64 `json:"tradeID"`
  30. Date string `json:"date"`
  31. Type string `json:"type"`
  32. Rate float64 `json:"rate,string"`
  33. Amount float64 `json:"amount,string"`
  34. Total float64 `json:"total,string"`
  35. }
  36. func main() {
  37. // 将 JSON 转换为结构体
  38. var THR TradeHistoryResponse
  39. err := json.Unmarshal([]byte(mjs), &THR)
  40. if err != nil {
  41. log.Fatal(err)
  42. }
  43. for _, v := range THR {
  44. fmt.Printf("%+v", v)
  45. fmt.Printf("\n")
  46. }
  47. }

这将按预期打印出所有的值。所以它没有问题将 JSON 值转换为浮点数/整数(这可能是我的第二个猜测)。

你确定你没有以任何方式修改 Body 吗?你给出的示例是否涵盖了所有边缘情况?

你可以添加以下代码:

  1. fmt.Println(string(body))

到第二个错误块,并在这里记录它给出的错误。

另外,你使用的是哪个版本的 Go?我不排除 encoding/json 在不同版本之间发生了变化的可能性。最后,如果确实是这种情况,简单的解决方法是将响应作为字符串处理,删除所有空格,并在“}{”处分割,如下所示:

  1. fmtBody := strings.Replace(string(body), "\n", "", -1)
  2. fmtBody = strings.Replace(string(fmtBody), " ", "", -1)
  3. fmtBody = strings.Replace(string(fmtBody), "[", "", -1)
  4. fmtBody = strings.Replace(string(fmtBody), "]", "", -1)
  5. var goArrOfYourJsonsObj []string = strings.Split(fmtBody, "},{")
  6. for k, _ := range goArrOfYourJsonsObj {
  7. goArrOfYourJsonsObj[k] += "}"
  8. }

现在,你的 JSON 对象已经整齐地分隔成一个 Go 数组,类型为字符串,可以在 Unmarshal 中使用 []byte(val)。

英文:

I didn't think unmarhsalling an array in a JSON like you intended actually works but to the props of encoding/json it does. Example code:
package main

  1. import (
  2. "encoding/json"
  3. "fmt"
  4. "log"
  5. )
  6. var mjs string = "[" +
  7. "{" +
  8. `"globalTradeID": 64201000,
  9. "tradeID": 549285,
  10. "date": "2016-11-11 23:51:58",
  11. "type": "buy",
  12. "rate": "10.33999779",
  13. "amount": "0.02176472",
  14. "total": "0.22504715"
  15. },
  16. {
  17. "globalTradeID": 64200631,
  18. "tradeID": 549284,
  19. "date": "2016-11-11 23:48:39",
  20. "type": "buy",
  21. "rate": "10.33999822",
  22. "amount": "0.18211700",
  23. "total": "1.88308945"
  24. }
  25. ]`
  26. type TradeHistoryResponse []TradeHistoryInfo
  27. type TradeHistoryInfo struct {
  28. GlobalTradeID int64 `json:"globalTradeID"`
  29. TradeID int64 `json:"tradeID"`
  30. Date string `json:"date"`
  31. Type string `json:"type"`
  32. Rate float64 `json:"rate,string"`
  33. Amount float64 `json:"amount,string"`
  34. Total float64 `json:"total,string"`
  35. }
  36. func main() {
  37. //Convert JSON to struct
  38. var THR TradeHistoryResponse
  39. err := json.Unmarshal([]byte(mjs), &THR)
  40. if err != nil {
  41. log.Fatal(err)
  42. }
  43. for _, v := range THR {
  44. fmt.Printf("%+v", v)
  45. fmt.Printf("\n")
  46. }
  47. }

This prints out all the values as expected. So it doesn't have a problem converting the json values to float/int either (which would have been my second guess).

Are you sure you aren't modifying the Body in any way ? And that the example you give cover all edge cases ?

Could you add:

  1. fmt.Println(string(body))

to the second error block and log the error it give here.

Also what version of go are you using ? I wouldn't exclude the possibility of encoding/json to have changed between versions. In the end, if this is indeed the case the easy fix would be taking your response as a string, removing all whitespaces and splitting at "}'{" as in:

  1. fmtBody := strings.Replace(string(body), "\n", "", -1)
  2. fmtBody = strings.Replace(string(fmtBody), "\w", "", -1)
  3. fmtBody = strings.Replace(string(fmtBody), "[", "", -1)
  4. fmtBody = strings.Replace(string(fmtBody), "]", "", -1)
  5. var goArrOfYourJsonsObj []String = strings.Split(fmtBody, "},{")
  6. for k, _ := range goArrOfYourJsonsObj {
  7. goArrOfYourJsonsObj[k] += "}"
  8. }

And now you have your JSON objects neatly separated into a go array of types String which, can be used in Unmarshall as []byte(val).

答案2

得分: 0

TradeHistoryResponse 是一个类型而不是一个变量,你需要创建一个类型为 TradeHistoryResponse 的变量,像这样:

  1. var th TradeHistoryResponse
  2. // 将 JSON 转换为结构体
  3. err = json.Unmarshal(body, &th)
  4. // ...
  5. fmt.Printf("%+v\n", th)

请注意,这只是一个示例代码,你需要根据实际情况进行适当的修改。

英文:

TradeHistoryResponse is a type no a variable, you have to create a var of type TradeHistoryResponse, like this:

  1. var th TradeHistoryResponse
  2. //Convert JSON to struct
  3. err = json.Unmarshal(body, &th)
  4. // ...
  5. fmt.Printf("%+v\n", th)

huangapple
  • 本文由 发表于 2016年11月16日 09:09:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/40622459.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定