英文:
Unmarshal json array to struct
问题
我有一个自定义值的数组:
[
1,
"test",
{ "a" : "b" }
]
我可以将其解组为 []interface{},但这不是我想要的。
我想将这个数组解组为结构体:
type MyType struct {
Count int
Name string
Relation map[string]string
}
在Go语言中,是否可以使用标准库或第三方库实现这个功能?
英文:
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?
答案1
得分: 4
另外的答案似乎太复杂了,这里是另一种方法:
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
英文:
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)
}
答案2
得分: 3
你可以使用github.com/ugorji/go/codec库,它可以将数组解组为结构体:
将结构体编码为数组,并从数据流中的数组解码为结构体
尽管该库宣称是“encoding/json”的“插拔替换”,但只是针对json:
标签而言。因此,您需要使用codec.Decoder
而不是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)
}
英文:
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)
}
答案3
得分: 1
这是一个元组,将元组解组为结构体是完全可以的,只是encoding/json
不支持这样做。
不过我们可以使用以下辅助函数,它会遍历结构体的字段并将其解组:
// UnmarshalJSONTuple 将 JSON 列表(元组)解组为结构体。
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("元组的字段数过多(%v),超过了 %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
}
因此,你只需要提供UnmarshalJSON
方法:
func (this *MyType) UnmarshalJSON(text []byte) (err error) {
return UnmarshalJSONTuple(text, this)
}
这是完整的示例:http://play.golang.org/p/QVA-1ynn15
英文:
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
答案4
得分: 0
由于你的 JSON 在数组中保存了不同类型的值,因此无法简单地使用 Go 解析它。如果你可以控制 JSON 输入的格式,请将这三个值包装在 {}
中以形成一个对象,如下所示:
[
{
"Count": 1,
"Name": "test",
"Relation": { "a" : "b" }
}
]
然后解析到你的结构体中应该就可以工作了。
如果你无法控制 JSON 输入,请将其解析为 []interface{}
,然后手动将值分配给你的结构体。尽管这可能会变得棘手,取决于你想要支持的可能响应的复杂性。
请注意,这个问题指向了 Golang JSON 解析方法的一个核心限制,因此据我所知,它也无法通过库来解决。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论