5

I have JSON that looks like this:

{
    "a": [
          [
              "12.58861425",
              10.52046452
          ],
          [
              "12.58861426",
              4.1073
          ]
        ]
    "b": [
          [
              "12.58861425",
              10.52046452
          ],
          [
              "12.58861426",
              4.1073
          ]
        ]
    "c": "true"
    "d": 1234
}
        

I want to unmarshall this into a struct I created:

type OrderBook struct {
	A [][2]float32 `json:"a"`
	B [][2]float32 `json:"b"`
        C string `json:"c"`
	D uint32 `json:"d"`
}

//Note this won't work because the JSON array contains a string and a float value pair rather than only floats.

Normally I would then convert this JSON into a struct in Golang as so:

orders := new(OrderBook)
err = json.Unmarshal(JSON, &orders)

Since I can't define the type struct to match the JSON this won't work. Doing a bit of reading, I think Unmarshal-ing into an interface, and then using the interface data through type checking may be a solution.

Am I going in the right direction with this?
A template showing how I might go about using the data once it's in the interface would really help.

4
  • I would recommend against unmarshalling into an interface, there are simpler solutions to the same problem. Here's a couple suggestions that might get you moving towards an appropriate solution. So one option is to provide custom implementation of UnmarshalJSON (gist.github.com/mdwhatcott/8dd2eef0042f7f1c0cd8) where you would provide custom logic to convert the strings to doubles. The other would be to keep everything the same but define just those inner arrays as an []interface{}. You could also convert after this, just I would recommend being as specific as possible there. Commented Aug 9, 2016 at 22:28
  • For me, better for you to make standard JSON instead. Is the one who generate JSON is external program or your program? Commented Aug 10, 2016 at 4:17
  • I agree, if you have control over the structure of the json, that would be better still. But, as is usually the case you don't, and so you can use my answer. Commented Aug 10, 2016 at 4:40
  • @Apin Unfortunately these are external services generating the JSON. Commented Aug 10, 2016 at 7:08

1 Answer 1

9

Why not just leave out declaring the types of the A and B slices like so?

data := []byte(`{"a": [["12.58861425",10.52046452],["12.58861426",4.1073]],"b": [["12.58861425",10.52046452],["12.58861426",4.1073]],"c": "true","d": 1234}`)

type OrderBook struct {
    A [][2]interface{} `json:"a"`
    B [][2]interface{} `json:"b"`
    C string           `json:"c"`
    D uint32           `json:"d"`
}
orders := new(OrderBook)
err := json.Unmarshal(data, &orders)
if err != nil {
    fmt.Printf(err.Error())
} else {
    fmt.Printf("%s\n", orders.A[0][0].(string))     
    fmt.Printf("%f\n", orders.A[0][1].(float64))
}

There's an example in the playground: https://play.golang.org/p/0MUY-yOYII

I must disagree with evanmcdonnal, there are certainly use cases where where rolling your own Unmarshaller makes sense, this I do not believe is one of them. It doesn't get much simpler than what is shown here.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.