9

I have an array of custom values

[
    1,
    "test",
    { "a" : "b" }
]

I can unmarshal in to []interface{}, but it's not what I want.

I would like to unmarshal this array to struct

type MyType struct {
    Count int
    Name string
    Relation map[string]string
}

Is it possible in Go with standard or side libraries?

2
  • golang.org/pkg/encoding/json explains the details and contains examples. Commented Mar 20, 2014 at 9:48
  • 1
    @Volker I read it before and could not find there solution of my problem. Could you point me where exactly it explains how to solve such problem? What example exactly? Commented Mar 20, 2014 at 9:54

4 Answers 4

4

The other answers seem too complicated, here is another approach:

package main

import (
   "encoding/json"
   "fmt"
)

type myType struct {
   count int
   name string
   relation map[string]string
}

func (t *myType) UnmarshalJSON(b []byte) error {
   a := []interface{}{&t.count, &t.name, &t.relation}
   return json.Unmarshal(b, &a)
}

func main() {
   var t myType
   json.Unmarshal([]byte(`[1, "test", {"a": "b"}]`), &t)
   fmt.Printf("%+v\n", t)
}

https://eagain.net/articles/go-json-array-to-struct

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

Comments

3

You can use github.com/ugorji/go/codec, it can unmarshal array to a struct:

Encode a struct as an array, and decode struct from an array in the data stream

Although the library advertises "drop-in replacement for encoding/json" - it's only about the json: tag. So you have to use codec.Decoder instead of json.Unmarshal:

package main

import "fmt"
import "github.com/ugorji/go/codec"

type MyType struct {
    Count    int
    Name     string
    Relation map[string]string
}

func main() {
    x := &MyType{}
    data := []byte(`[1,"test",{"a":"b"}]`)
    codec.NewDecoderBytes(data, new(codec.JsonHandle)).Decode(x)
    fmt.Println(x)
}

1 Comment

Could you provide an example in your answer?
1

That is a tuple, and it's perfectly fine to unmarshal tuple into a structure, except that encoding/json doesn't support that.

However we can use the following helper function, which iterates over the fields of the structure and unmarshals them:

// UnmarshalJSONTuple unmarshals JSON list (tuple) into a struct.
func UnmarshalJSONTuple(text []byte, obj interface{}) (err error) {
    var list []json.RawMessage
    err = json.Unmarshal(text, &list)
    if err != nil {
        return
    }

    objValue := reflect.ValueOf(obj).Elem()
    if len(list) > objValue.Type().NumField() {
        return fmt.Errorf("tuple has too many fields (%v) for %v",
            len(list), objValue.Type().Name())
    }

    for i, elemText := range list {
        err = json.Unmarshal(elemText, objValue.Field(i).Addr().Interface())
        if err != nil {
            return
        }
    }
    return
}

So you only need to provide the UnmarshalJSON method:

func (this *MyType) UnmarshalJSON(text []byte) (err error) {
    return UnmarshalJSONTuple(text, this)
}

Here is the complete example: http://play.golang.org/p/QVA-1ynn15

Comments

0

since your json holds values of different types in an array it is not possible to parse this with go simply. If you have controll over how the json input is formatted, wrap the three values in {} to form an object, like so:

[
    {
        "Count": 1,
        "Name": "test",
        "Relation": { "a" : "b" }
     }
]

Then parsing into your struct should work.

If you have no controll over the json input. Parse it as []interface{} and then assign the values to your struct manually. Even though this might get tricky, depending on complexity of possible responses you'd like to support.

Please note, that this issue points to a core limitation of golangs json parsing method and that therefore - as far as I know - it can also not be solved by libraries.

3 Comments

no it does not work as far as I can see and the json you provided is not valid :( Assigning values manually is complicated, I'm looking for a library that would make it
you're right, I was missing keys in the json Object, sorry about that. Generally if you have problems like this, I suggest using a dummy instance of your targetvalue and Encode it, to see what kind of output go produces from it (and therefore expects to find as input to Decode)
look at github.com/likexian/simplejson, but I think it also can't solve your issue.

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.