Alteran
Alteran

Reputation: 111

Is it possible to Unmarshall a JSON which has varying field?

I am tring to get League of Legends champion informations from LOL static database. Link is given below.

Get info for specific hero

The problem is that i can only make request by hero names and all JSON responses are different from each other by only one field which is a "main" field; hero name. You can find problematic field as highlighted below: Aatrox is just a hero from 158 other

Also tree respresentation:

My goal is to get all hero informations with iteration by range of known hero names as slice. You can check the code. I need only a couple of fields but the main tag is varies with every new request.

func GetHeroInfo(heroName string) *LolHeroInfo {
getUrl := fmt.Sprintf("http://ddragon.leagueoflegends.com/cdn/12.2.1/data/en_US/champion/%s.json", heroName)
fmt.Println(getUrl)
resp, err := http.Get(getUrl)
if err != nil {
    fmt.Println(err)
    return nil
}
defer resp.Body.Close()
read, err := io.ReadAll(resp.Body)
if err != nil {
    fmt.Println(err)
    return nil
}
heroGoverted := LolHeroInfo{}
err = json.Unmarshal(read, &heroGoverted)
if err != nil {
    fmt.Println("unmarshall failed:", err)
    return nil
}
return &heroGoverted }

Struct type LolHeroInfo is structifyed from this link: mholt's JSON to struct

You can check JSON response for another hero eg: JSON response for Annie .

Is there any way to make an agnostic struct field/tag for a JSON field. I believe this will be very hard because encoding/json package needs to check for field for particular tag in that JSON but maybe you encountered this kind of problem before. Creating separate struct for each hero is impossible so i will drop this case if i can't find a solution.

Thanks in advance for help.

Upvotes: 0

Views: 79

Answers (2)

Alteran
Alteran

Reputation: 111

To solve problem, I used @dave 's solution.

I breake main struct into two separate struct. This way varying JSON field eliminated:

type LolHeroInfo struct {
Type    string                    `json:"type"`
Format  string                    `json:"format"`
Version string                    `json:"version"`
Data    map[string]HeroInfoStruct `json:"data"`

}

Second struct

heroInfo := lib.GetHeroInfo(lolHeroes[i])
    for _, v := range heroInfo.Data { //unmarshalled to first struct
        a := lib.HeroInfoStruct{} //data field; second struct
        a = v
        fmt.Println(a.Lore)// now i can reach to every field that i need
    }

Upvotes: 0

dave
dave

Reputation: 64657

Since you know it's just a single unknown key, you could just decode into a map[string]LolHeroInfo for the Data field, then do

heroGoverted := LolHeroInfo{}
for _, v := range decoded.Data {
    heroGoverted = v
}

Upvotes: 2

Related Questions