解码仅存在于数组中的JSON响应

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

Decoding a JSON response that exists only out of an array

问题

我有一个解码JSON响应的问题。我已经尝试解决这个问题几个星期了,但在网上找不到有效的解决方案。

这是我的Go代码,用于获取响应:

  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. "strconv"
  6. "encoding/json"
  7. "net/http"
  8. "io"
  9. )
  10. const (
  11. binanceUrl_0 = "https://api.binance.com"
  12. binanceUrl_1 = "https://api1.binance.com"
  13. binanceUrl_2 = "https://api2.binance.com"
  14. binanceUrl_3 = "https://api3.binance.com"
  15. //选择要使用的URL
  16. binanceUrl = binanceUrl_0
  17. binance_GetServerTime = binanceUrl + "/api/v3/time"
  18. binance_Ping = binanceUrl + "/api/v3/ping"
  19. binance_GetExhangeInfo = binanceUrl + "/api/v3/exchangeInfo"
  20. binance_GetExhangeInfo_Symbol = binanceUrl + "/api/v3/exchangeInfo?symbol=BNBBTC"
  21. binance_GetKlineData = binanceUrl + "/api/v1/klines"
  22. )
  23. type Binance_klines struct {
  24. OpenTime int64
  25. open float32
  26. high float32
  27. low float32
  28. close float32
  29. volume float32
  30. CloseTime int64
  31. QuoteVolume float32
  32. NumTrades int64
  33. TakerBaseVolume float32
  34. TakerQuoteVolume float32
  35. }
  36. func GetKlines_wEndTime(symbol string, interval string, limit int, endTime time.Time) ([]Binance_klines, error) {
  37. var url string
  38. url = binance_GetKlineData + "?" +
  39. "symbol=" + symbol +
  40. "&interval=" + interval +
  41. "&limit=" + strconv.FormatInt(int64(limit), 10) +
  42. "&endTime=" + strconv.FormatInt(endTime.Unix(),10 ) + "000"
  43. response, err := http.Get(url)
  44. if err != nil {
  45. return nil, err
  46. }
  47. data, err := respToKlines(response.Body)
  48. if err != nil {
  49. return nil, err
  50. }
  51. response.Body.Close()
  52. return data, nil
  53. }
  54. func respToKlines(data io.Reader) ([]Binance_klines, error) {
  55. var klines []Binance_klines
  56. var decoded []interface{}
  57. decoder := json.NewDecoder(data)
  58. err := decoder.Decode(&decoded)
  59. if err != nil {
  60. return nil, err
  61. }
  62. for i:=0; i<len(decoded); i++ {
  63. to_parse := decoded[i]
  64. fmt.Println("to_parse",to_parse)
  65. var kline Binance_klines
  66. kline = to_parse.(Binance_klines)
  67. fmt.Println("kline",kline)
  68. }
  69. return klines, nil
  70. }
  71. func main() {
  72. result, err := GetKlines_wEndTime("BTCEUR", "1m", 3, time.Now())
  73. fmt.Println(result, err)
  74. }

这是我得到的响应(从字节转换为字符串):

  1. [[1664277480000,"20980.42000000","20984.06000000","20966.57000000","20970.14000000","6.10441000",1664277539999,"128041.93403330",142,"2.97844000","62486.29173860","0"],[1664277540000,"20969.14000000","20976.08000000","20955.69000000","20970.15000000","3.17365000",1664277599999,"66548.64583140",88,"2.39827000","50292.47196580","0"],[1664277600000,"20970.15000000","20970.15000000","20970.15000000","20970.15000000","0.00000000",1664277659999,"0.00000000",0,"0.00000000","0.00000000","0"]]

我的问题是,我做错了什么?当我使用类似https://mholt.github.io/json-to-go/的工具时,它要求我创建一个[][]interface{}。但是在我的循环中,你可以看到它打印出一个(在我看来)有效的[]interface{},但我无法将其转换为类型为Binance_Klines的结构体。这一行有问题吗?

  1. kline = to_parse.(Binance_klines)

还是我只是误解了一些东西?我需要做出什么改变才能使用类型断言?或者直接将其解码为正确的结构体?

英文:

I have an problem with decoding an JSON respone. I've tried to solve this problem for a couple off weeks and can't find an working solution online.

This is my Go code that gets the response:

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;time&quot;
  5. &quot;strconv&quot;
  6. &quot;encoding/json&quot;
  7. &quot;net/http&quot;
  8. &quot;io&quot;
  9. )
  10. const (
  11. binanceUrl_0 = &quot;https://api.binance.com&quot;
  12. binanceUrl_1 = &quot;https://api1.binance.com&quot;
  13. binanceUrl_2 = &quot;https://api2.binance.com&quot;
  14. binanceUrl_3 = &quot;https://api3.binance.com&quot;
  15. //select which url to use
  16. binanceUrl = binanceUrl_0
  17. binance_GetServerTime = binanceUrl + &quot;/api/v3/time&quot;
  18. binance_Ping = binanceUrl + &quot;/api/v3/ping&quot;
  19. binance_GetExhangeInfo = binanceUrl + &quot;/api/v3/exchangeInfo&quot;
  20. binance_GetExhangeInfo_Symbol = binanceUrl + &quot;/api/v3/exchangeInfo?symbol=BNBBTC&quot;
  21. binance_GetKlineData = binanceUrl + &quot;/api/v1/klines&quot;
  22. )
  23. type Binance_klines struct {
  24. OpenTime int64
  25. open float32
  26. high float32
  27. low float32
  28. close float32
  29. volume float32
  30. CloseTime int64
  31. QuoteVolume float32
  32. NumTrades int64
  33. TakerBaseVolume float32
  34. TakerQuoteVolume float32
  35. }
  36. func GetKlines_wEndTime(symbol string, interval string, limit int, endTime time.Time) ([]Binance_klines, error) {
  37. var url string
  38. url = binance_GetKlineData + &quot;?&quot; +
  39. &quot;symbol=&quot; + symbol +
  40. &quot;&amp;interval=&quot; + interval +
  41. &quot;&amp;limit=&quot; + strconv.FormatInt(int64(limit), 10) +
  42. &quot;&amp;endTime=&quot; + strconv.FormatInt(endTime.Unix(),10 ) + &quot;000&quot;
  43. response, err := http.Get(url)
  44. if err != nil {
  45. return nil, err
  46. }
  47. data, err := respToKlines(response.Body)
  48. if err != nil {
  49. return nil, err
  50. }
  51. response.Body.Close()
  52. return data, nil
  53. }
  54. func respToKlines(data io.Reader) ([]Binance_klines, error) {
  55. var klines []Binance_klines
  56. var decoded []interface{}
  57. decoder := json.NewDecoder(data)
  58. err := decoder.Decode(&amp;decoded)
  59. if err != nil {
  60. return nil, err
  61. }
  62. //Attempt 1:
  63. //kline = (decoded).([]Binance_klines)
  64. //err: invalid operation: (decoded) (variable of type []interface{}) is not an interface
  65. //Attempt 2:
  66. for i:=0; i&lt;len(decoded); i++ {
  67. to_parse := decoded[i]
  68. fmt.Println(&quot;to_parse&quot;,to_parse)
  69. //prints: to_parse [1.66427838e+12 20982.91000000 20992.61000000 20977.90000000 20980.95000000 0.68063000 1.664278439999e+12 14282.75833530 57 0.27942000 5864.01792110 0]
  70. var kline Binance_klines
  71. kline = (to_parse).(Binance_klines)
  72. //err: interface conversion: interface {} is []interface {}, not dsBinance.Binance_klines
  73. fmt.Println(&quot;kline&quot;,kline)
  74. }
  75. return klines, nil
  76. }
  77. func main() {
  78. result, err := GetKlines_wEndTime( &quot;BTCEUR&quot;, &quot;1m&quot;, 3, time.Now() )
  79. fmt.Println(result, err)
  80. }

This is an reponse I get (converted to string from bytes):

  1. [[1664277480000,&quot;20980.42000000&quot;,&quot;20984.06000000&quot;,&quot;20966.57000000&quot;,&quot;20970.14000000&quot;,&quot;6.10441000&quot;,1664277539999,&quot;128041.93403330&quot;,142,&quot;2.97844000&quot;,&quot;62486.29173860&quot;,&quot;0&quot;],[1664277540000,&quot;20969.14000000&quot;,&quot;20976.08000000&quot;,&quot;20955.69000000&quot;,&quot;20970.15000000&quot;,&quot;3.17365000&quot;,1664277599999,&quot;66548.64583140&quot;,88,&quot;2.39827000&quot;,&quot;50292.47196580&quot;,&quot;0&quot;],[1664277600000,&quot;20970.15000000&quot;,&quot;20970.15000000&quot;,&quot;20970.15000000&quot;,&quot;20970.15000000&quot;,&quot;0.00000000&quot;,1664277659999,&quot;0.00000000&quot;,0,&quot;0.00000000&quot;,&quot;0.00000000&quot;,&quot;0&quot;]]

My question is, what am I doing wrong? When I use a tool like https://mholt.github.io/json-to-go/, it wants me to make an [][]interface{}. But in my for loop you can see that it prints an (in my eyes) a valid: []interface{} but i cannot convert it to an struct of type Binance_Klines.
Is something wrong with this line:

  1. kline = (to_parse).(Binance_klines)

Or am I just misunderstanding something? What do I need to change to be able to use the type assertion? Or to just decode it at once to the right struct?

答案1

得分: 2

你不能将[]interface{}转换为Binance_klines。所以kline = (to_parse).(Binance_klines)会失败。你需要自己编写转换代码。

返回的数据是一个二维数组。以下是你格式化后的 JSON 负载。类型是stringfloat64的混合,所以 Go 使用interface{}来存储这些值。

  1. [
  2. [
  3. 1664277480000,
  4. "20980.42000000",
  5. "20984.06000000",
  6. "20966.57000000",
  7. "20970.14000000",
  8. "6.10441000",
  9. 1664277539999,
  10. "128041.93403330",
  11. 142,
  12. "2.97844000",
  13. "62486.29173860",
  14. "0"
  15. ],
  16. [
  17. 1664277540000,
  18. "20969.14000000",
  19. "20976.08000000",
  20. "20955.69000000",
  21. "20970.15000000",
  22. "3.17365000",
  23. 1664277599999,
  24. "66548.64583140",
  25. 88,
  26. "2.39827000",
  27. "50292.47196580",
  28. "0"
  29. ],
  30. [
  31. 1664277600000,
  32. "20970.15000000",
  33. "20970.15000000",
  34. "20970.15000000",
  35. "20970.15000000",
  36. "0.00000000",
  37. 1664277659999,
  38. "0.00000000",
  39. 0,
  40. "0.00000000",
  41. "0.00000000",
  42. "0"
  43. ]
  44. ]

JSON 解码器无法将其转换为你的Binance_klines结构体。但你可以自己重写默认的解组行为。

首先,我创建了一个类型,用于处理有时带引号的数字。

  1. type BinanceNumber string
  2. func (b *BinanceNumber) UnmarshalJSON(data []byte) error {
  3. *b = BinanceNumber(strings.Trim(string(data), "\""))
  4. return nil
  5. }
  6. func (b BinanceNumber) Float64() float64 {
  7. f, err := strconv.ParseFloat(string(b), 64)
  8. if err != nil {
  9. panic(err)
  10. }
  11. return f
  12. }
  13. func (b BinanceNumber) Int64() int64 {
  14. i, err := strconv.ParseInt(string(b), 10, 64)
  15. if err != nil {
  16. panic(err)
  17. }
  18. return i
  19. }

然后,你重写Binance_klines的解组方法。

  1. func (b *Binance_klines) UnmarshalJSON(data []byte) error {
  2. var array []BinanceNumber
  3. err := json.Unmarshal(data, &array)
  4. if err != nil {
  5. return err
  6. }
  7. b.OpenTime = array[0].Int64()
  8. b.Open = float32(array[1].Float64())
  9. b.High = float32(array[2].Float64())
  10. b.Low = float32(array[3].Float64())
  11. b.Close = float32(array[4].Float64())
  12. b.Volume = float32(array[5].Float64())
  13. b.CloseTime = array[6].Int64()
  14. b.QuoteVolume = float32(array[7].Float64())
  15. b.NumTrades = array[8].Int64()
  16. b.TakerBaseVolume = float32(array[9].Float64())
  17. b.TakerQuoteVolume = float32(array[10].Float64())
  18. return nil
  19. }

将它们整合在一起:https://go.dev/play/p/SGGbWEUFxJr。

英文:

You cannot cast []interface{} to Binance_klines. So kline = (to_parse).(Binance_klines) fails. You have to write the translation yourself.


The data returned is a 2 dimensional array. Here is the json payload you have formatted. The types are a mix of string and float64, so Go uses interface{} to store the values.

  1. [
  2. [
  3. 1664277480000,
  4. &quot;20980.42000000&quot;,
  5. &quot;20984.06000000&quot;,
  6. &quot;20966.57000000&quot;,
  7. &quot;20970.14000000&quot;,
  8. &quot;6.10441000&quot;,
  9. 1664277539999,
  10. &quot;128041.93403330&quot;,
  11. 142,
  12. &quot;2.97844000&quot;,
  13. &quot;62486.29173860&quot;,
  14. &quot;0&quot;
  15. ],
  16. [
  17. 1664277540000,
  18. &quot;20969.14000000&quot;,
  19. &quot;20976.08000000&quot;,
  20. &quot;20955.69000000&quot;,
  21. &quot;20970.15000000&quot;,
  22. &quot;3.17365000&quot;,
  23. 1664277599999,
  24. &quot;66548.64583140&quot;,
  25. 88,
  26. &quot;2.39827000&quot;,
  27. &quot;50292.47196580&quot;,
  28. &quot;0&quot;
  29. ],
  30. [
  31. 1664277600000,
  32. &quot;20970.15000000&quot;,
  33. &quot;20970.15000000&quot;,
  34. &quot;20970.15000000&quot;,
  35. &quot;20970.15000000&quot;,
  36. &quot;0.00000000&quot;,
  37. 1664277659999,
  38. &quot;0.00000000&quot;,
  39. 0,
  40. &quot;0.00000000&quot;,
  41. &quot;0.00000000&quot;,
  42. &quot;0&quot;
  43. ]
  44. ]

The json decoder cannot convert this into your Binance_klines struct. But you can override the default unmarshal behavior yourself.

First I made a type for the sometimes quoted numbers, sometimes not.

  1. type BinanceNumber string
  2. func (b *BinanceNumber) UnmarshalJSON(data []byte) error {
  3. *b = BinanceNumber(strings.Trim(string(data), &quot;\&quot;&quot;))
  4. return nil
  5. }
  6. func (b BinanceNumber) Float64() float64 {
  7. f, err := strconv.ParseFloat(string(b), 64)
  8. if err != nil {
  9. panic(err)
  10. }
  11. return f
  12. }
  13. func (b BinanceNumber) Int64() int64 {
  14. i, err := strconv.ParseInt(string(b), 10, 64)
  15. if err != nil {
  16. panic(err)
  17. }
  18. return i
  19. }

Then you override the Binance_klines unmarshal.

  1. func (b *Binance_klines) UnmarshalJSON(data []byte) error {
  2. var array []BinanceNumber
  3. err := json.Unmarshal(data, &amp;array)
  4. if err != nil {
  5. return err
  6. }
  7. b.OpenTime = array[0].Int64()
  8. b.Open = float32(array[1].Float64())
  9. b.High = float32(array[2].Float64())
  10. b.Low = float32(array[3].Float64())
  11. b.Close = float32(array[4].Float64())
  12. b.Volume = float32(array[5].Float64())
  13. b.CloseTime = array[6].Int64()
  14. b.QuoteVolume = float32(array[7].Float64())
  15. b.NumTrades = array[8].Int64()
  16. b.TakerBaseVolume = float32(array[9].Float64())
  17. b.TakerQuoteVolume = float32(array[10].Float64())
  18. return nil
  19. }

Putting it all together: https://go.dev/play/p/SGGbWEUFxJr.

答案2

得分: 0

这部分代码需要进行修改:

  1. var kline Binance_klines
  2. kline.OpenTimer = to_parse[0].(int64)
  3. kline.open, _ = strconv.ParseFloat(to_parse[1].(string), 64)
  4. ...

你收到的不是 Binance_klines 结构体的 JSON 表示,而是一个包含数字和字符串的切片。

英文:

This part:

  1. var kline Binance_klines
  2. kline = (to_parse).(Binance_klines)

needs to become

  1. var kline Binance_klines
  2. kline.OpenTimer = to_parse[0].(int64)
  3. kline.open = strconv.ParseFloat(to_parse[1].(string), 64)
  4. ...

You are not receiving the json representation of your Binance_klines struct but a slice of any (a mix or numbers and strings).

huangapple
  • 本文由 发表于 2022年9月27日 19:49:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/73867082.html
匿名

发表评论

匿名网友

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

确定