-1

Assume I have this data:

{
"code": 10000,
"msg": "Successful request processing",
"asks": [ 
    [
        "0.03434400",
        "0.31100000"
    ],
    [
        "0.03436300",
        "0.18900000"
    ],
    [

],
"bids": [ 
    [
        "0.03427400", 
        "0.21100000"  
    ],...

Thanks to the Go to JSON converter, I know it can be parsed like this (working, in my script):

type AutoGenerated struct {
Code int        `json:"code"`
Msg  string     `json:"msg"`
Asks [][]string `json:"asks"`
Bids [][]string `json:"bids"`
}

I'd rather parse it like this:

type Box struct {
Number int `json:"code"`
Message string `json:"msg"` 
Asks []MarketData `json:"asks"`
Bids []MarketData  `json:"bids"`
}

type MarketData struct {
Sell []string
}

Or, even better, this (assuming Box struct stays the same):

type MarketData struct {
SellPrice string
SellQuantity string
}

The problem is that if I try to print the above using price :=response.Asks[0].SellPrice, or using the previous example, response.Asks[0].Sell, I get an empty struct.

Why doesn't this work? It seems like legitimate go, to me. It builds fine, but whenever I try to run it, it prints empty braces.

jumar
  • 309
  • 1
  • 2
  • 14

2 Answers2

3
package main

import (
    "encoding/json"
    "fmt"
)

var j = `{
    "code": 10000,
    "msg": "Successful request processing",
    "asks": [ 
        [
            "0.03434400",
            "0.31100000"
        ],
        [
            "0.03436300",
            "0.18900000"
        ]


    ],
    "bids": [ 
        [
            "0.03427400", 
            "0.21100000"  
        ]
        ]
    }
        `

type Box struct {
    Number  int          `json:"code"`
    Message string       `json:"msg"`
    Asks    []MarketData `json:"asks"`
    Bids    []MarketData `json:"bids"`
}

type MarketData struct {
    SellPrice    string
    SellQuantity string
}

func (md *MarketData) UnmarshalJSON(d []byte) error {
    val := []string{}
    err := json.Unmarshal(d, &val)
    if err != nil {
        return err
    }
    if len(val) != 2 {
        return fmt.Errorf("MarketData unmarshal error len != 2")
    }
    md.SellPrice = val[0]
    md.SellQuantity = val[1]
    return nil
}

func main() {
    ins := new(Box)
    err := json.Unmarshal([]byte(j), ins)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%+v\n", ins)
}

https://play.golang.org/p/EKH3ICJJuZ_W

beiping96
  • 644
  • 3
  • 12
  • That works! I see now that the problem is in my decoding; you can see my code below (editing out the func main boilerplate). var myClient = &http.Client{Timeout: 10 * time.Second} func getJson(url string, target interface{}) error { r, err := myClient.Get(url) if err != nil { return err } defer r.Body.Close() return json.NewDecoder(r.Body).Decode(target) } func main() { response := new(Box) url := "doesn't matter" getJson(url, response) – jumar Apr 26 '19 at 03:12
  • I think I may just use your code as is, however. – jumar Apr 26 '19 at 03:17
  • @jumar just need to achieve this https://godoc.org/encoding/json#Unmarshaler interface for `MarketData ` – beiping96 Apr 26 '19 at 03:27
1

You are changing the structure of the data, of course it will not parse the same way.

You can probably do it like this:

type MarketDataInput []string

This doesn't give you useful field names.

If you can't change the structure of the input data, you can probably do this instead:

func (m MarketData) SellPrice() string {
    return m[0]
}

func (m MarketData) SellQuantity() string {
    return m[1]
}

But overall this just seems like a bad way of handling the data. You should probably transform it to a different data structure after you parse it to json.

type MarketDataInput []string

type MarketData struct {
    SellPrice float64
    SellQuantity float64
}

func MarketDataFromInputs(inputs []MarketDataInput) []MarketData {
    var output = make([]MarketData, 0, len(inputs))
    for _, input := range inputs {
        var item MarketData
        item.SellPrice, _ = strconv.ParseFloat(input[0], 64)
        item.SellQuantity, _ = strconv.ParseFloat(input[1], 64)
        output = append(output, item)
    }
    return output
}

Now you have the data in a more useful structure that you can process better.

user10753492
  • 720
  • 4
  • 8