0

I'm trying to parse the first record in an embedded JSON array and create an object based on a subset of those properties. I have this working, but based on this question, I have to think there is a more elegant/less brittle way of doing this. For a bit more background, this is a result set from a call to the musicbrainz JSON web service, and I am treating the first artists record as the artist I am looking for.

The format of the JSON is like this:

{
    "created": "2014-10-08T23:55:54.343Z",
    "count": 458,
    "offset": 0,
    "artists": [{
        "id": "83b9cbe7-9857-49e2-ab8e-b57b01038103",
        "type": "Group",
        "score": "100",
        "name": "Pearl Jam",
        "sort-name": "Pearl Jam",
        "country": "US",
        "area": {
            "id": "489ce91b-6658-3307-9877-795b68554c98",
            "name": "United States",
            "sort-name": "United States"
        },
        "begin-area": {
            "id": "10adc6b5-63bf-4b4e-993e-ed83b05c22fc",
            "name": "Seattle",
            "sort-name": "Seattle"
        },
        "life-span": {
            "begin": "1990",
            "ended": null
        },
        "aliases": [],
        "tags": []
    },
    ...
}

Here's the code I have so far. I'd like to be able to use my ArtistCollection type to get around some of the interface{} stuff, but I'm stuck as to how. I also don't want to bother with mapping all of the properties of the artist record, I'm only interested in the "name" and "id" values.

package main

import (
    "fmt"
    "encoding/json"
    )

type Artist struct {
    Id string
    Name string
}

type ArtistCollection struct {
    Artists []Artist
}

func main() {
    raw := //json formatted byte array
    var topLevel interface{}
    err := json.Unmarshal(raw, &topLevel)
    if err != nil {
        fmt.Println("Uh oh")
    } else {
        m := topLevel.(map[string]interface{})
        //this seems really hacky/brittle, there has to be a better way?
        result := (m["artists"].([]interface{})[0]).(map[string]interface{})
        artist := new(Artist)
        artist.Id = result["id"].(string)
        artist.Name = result["name"].(string)
        fmt.Println(artist)
    }
}

Requisite go playground link

1 Answer 1

2

Define a type that matches the structure of the JSON and unmarshal to a value of that type. I use an anonymous type below. Use an array of length one to grab the first artist record:

package main

import (
    "encoding/json"
    "fmt"
)

type Artist struct {
    Id   string
    Name string
}

func main() {
    raw := // JSON formatted byte array
    var result struct {
        Artists artist
    }
    err := json.Unmarshal(raw, &result)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Printf("%#v\n", result.Artists[0])
}

playground

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

2 Comments

That makes sense, thank you! I, for some reason, was not expecting it to be possible to marshal to a type that only partially represented the JSON.
Note the last edit (at the time of this comment) is incorrect; it does not match the code on the playground link, and will not compile. It should be Artists []Artist as in the other answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.