Unmarshal JSON with some known, and some unknown field names
Unmarshal twice
One option is to unmarshal twice: once into a value of type Foo
and once into a value of type map[string]interface{}
and removing the keys "a"
and "b"
:
type Foo struct {
A int `json:"a"`
B int `json:"b"`
X map[string]interface{} `json:"-"` // Rest of the fields should go here.
}
func main() {
s := `{"a":1, "b":2, "x":1, "y":1}`
f := Foo{}
if err := json.Unmarshal([]byte(s), &f); err != nil {
panic(err)
}
if err := json.Unmarshal([]byte(s), &f.X); err != nil {
panic(err)
}
delete(f.X, "a")
delete(f.X, "b")
fmt.Printf("%+v", f)
}
Output (try it on the Go Playground):
{A:1 B:2 X:map[x:1 y:1]}
Unmarshal once and manual handling
Another option is to unmarshal once into an map[string]interface{}
and handle the Foo.A
and Foo.B
fields manually:
type Foo struct {
A int `json:"a"`
B int `json:"b"`
X map[string]interface{} `json:"-"` // Rest of the fields should go here.
}
func main() {
s := `{"a":1, "b":2, "x":1, "y":1}`
f := Foo{}
if err := json.Unmarshal([]byte(s), &f.X); err != nil {
panic(err)
}
if n, ok := f.X["a"].(float64); ok {
f.A = int(n)
}
if n, ok := f.X["b"].(float64); ok {
f.B = int(n)
}
delete(f.X, "a")
delete(f.X, "b")
fmt.Printf("%+v", f)
}
Output is the same (Go Playground):
{A:1 B:2 X:map[x:1 y:1]}
It's not nice, but you could to it by implementing Unmarshaler
:
type _Foo Foo
func (f *Foo) UnmarshalJSON(bs []byte) (err error) {
foo := _Foo{}
if err = json.Unmarshal(bs, &foo); err == nil {
*f = Foo(foo)
}
m := make(map[string]interface{})
if err = json.Unmarshal(bs, &m); err == nil {
delete(m, "a")
delete(m, "b")
f.X = m
}
return err
}
The type _Foo
is necessary to avoid recursion while decoding.
Simplest way is to use an interface like this:
var f interface{}
s := `{"a":1, "b":2, "x":1, "y":1}`
if err := json.Unmarshal([]byte(s), &f); err != nil {
panic(err)
}
Go Playground example
I use interface to unmarshal uncertain type json.
bytes := []byte(`{"name":"Liam","gender":1, "salary": 1}`)
var p2 interface{}
json.Unmarshal(bytes, &p2)
m := p2.(map[string]interface{})
fmt.Println(m)