5

I have the following JSON

{"student_number":1234567, "name":"John Doe", "subjects":"Chemistry-Maths-History-Geography"}

I would like to unmarshal it in a struct, where one item (the subjects) are split on '-' into a []string.

type Student struct {
  StudentNumber int       `json:"student_number"`
  Name          string    `json:"name"`
  Subjects []string 
}

I have attempted several different ways of achieving this with custom Unmarshalling using strings.Split(), but have not succeeded so far.

Is there any way to achieve this in the unmarshalling process? Or will I need to simply unmarshal as is and make the conversion afterward?

1
  • 2
    Of course you can write your own UnmarshalJSON method to do this. But why bother? Plain and straight unmarshaling into a string and splitting afterwords is so much simpler, easier to test and less error prone. Commented Nov 7, 2018 at 9:09

1 Answer 1

19

Easiest would be to define your own string slice type and implement json.Unmarshaler on that:

type strslice []string

func (ss *strslice) UnmarshalJSON(data []byte) error {
    var s string
    if err := json.Unmarshal(data, &s); err != nil {
        return err
    }
    *ss = strings.Split(s, "-")
    return nil
}

And use this in your struct:

type Student struct {
    StudentNumber int      `json:"student_number"`
    Name          string   `json:"name"`
    Subjects      strslice `json:"subjects"`
}

And then it'll work:

func main() {
    var s Student
    err := json.Unmarshal([]byte(src), &s)
    fmt.Println(s, err)
}

const src = `{"student_number":1234567, "name":"John Doe", "subjects":"Chemistry-Maths-History-Geography"}`

Output (try it on the Go Playground):

{1234567 John Doe [Chemistry Maths History Geography]} <nil>
Sign up to request clarification or add additional context in comments.

2 Comments

Works like a sunshine. Thanks! Would you agree with Volker's comment that doing it post-unmarshalling is actually a better solution?
@MarcoW Depends on your use case. If you only need the slice once, you may leave the field as a string in the struct, and add a method to the struct that splits it (or just split the field's value where needed). If you need it multiple times, the splitted parts may be stored (e.g. in an additional field), but at that point this solution is simpler.

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.