1

I want to parse the following JSON output:

{
    "total":5689,
    "result":{
        "6581":{
            "percent":37.79,
            "count":2150
        },
        "6591":{
            "percent":35.31,
            "count":2009
        },
        "6601":{
            "percent":26.89,
            "count":1530
        }
    }
}

I have read that JSON can be parsed into a struct if the format is known:

package main

import (
    "encoding/json"
    "fmt"
    "os"
)

type VoteResult struct {
    Total  int `json:"total"`
    Result struct {
        Efid1 struct {
            Percent float64 `json:"percent"`
            Count   int     `json:"count"`
        }
        Efid2 struct {
            Percent float64 `json:"percent"`
            Count   int     `json:"count"`
        }
        Efid3 struct {
            Percent float64 `json:"percent"`
            Count   int     `json:"count"`
        }
    }
}

func main() {
    b := []byte(`{"total":5689,"result":{"6581":{"percent":37.79,"count":2150}
    ,"6591":{"percent":35.31,"count":2009},"6601":{"percent":26.89,"count":1530}}}`)

    var v VoteResult

    err := json.Unmarshal(b, &v)
    if err != nil {
        fmt.Fprintf(os.Stderr, "%v\n", err)
        os.Exit(1)
    }

    fmt.Println(v)
}

Go Playground

This is the output, but something is wrong as the nested structs are not filled with data:

{5689 {{0 0} {0 0} {0 0}}}

What am I doing wrong?

1 Answer 1

1

The result part of the JSON is a dictionary mapping strings to objects. Try this instead (https://play.golang.org/p/BCNHw-OH2I):

type VoteResult struct {
    Total  int `json:"total"`
    Result map[string]struct {
        Percent float64 `json:"percent"`
        Count   int     `json:"count"`
    }
}

EDIT

As an alternative, if those strings are truly fixed, you could do this:

type VoteResult struct {
    Total  int `json:"total"`
    Result struct {
        Efid1 struct {
            Percent float64 `json:"percent"`
            Count   int     `json:"count"`
        } `json:"6581"`
        Efid2 struct {
            Percent float64 `json:"percent"`
            Count   int     `json:"count"`
        } `json:"6591"`
        Efid3 struct {
            Percent float64 `json:"percent"`
            Count   int     `json:"count"`
        } `json:"6601"`
    }
}

Here we've just decided that Efid1 has the JSON key 6591, etc. But I suspect a map of strings to structs is a better fit for the data structure you have.

6
  • He's just missing a tag. Changing his data type to something dynamic isn't a good solution to that problem. Commented Jul 25, 2016 at 23:06
  • @evanmcdonnal I'm not sure what makes you think that. The default JSON tag for Result is result already. Adding a tag shouldn't (and doesn't when I just tried it) make a difference.
    – user94559
    Commented Jul 25, 2016 at 23:07
  • yeah you're right, that works fine and my code was wrong, didn't read the post closely enough. Result needs to be a dictionary because the objects have keys. He could do something like what I have but it doesn't really make sense imo (the three inner structs would also need tags and I bet their names change from one response to another). Commented Jul 25, 2016 at 23:09
  • @evanmcdonnal Yeah, I added an alternative that shows that approach, but as you said, it's probably not the right thing.
    – user94559
    Commented Jul 25, 2016 at 23:10
  • Thanks. I could not figure out where the tags for the inner structs should go, I put them after struct but that did not work. However, I like the first example much better as this is more compact and will also work when name of inner structs change.
    – John Smith
    Commented Jul 25, 2016 at 23:39

Not the answer you're looking for? Browse other questions tagged or ask your own question.