JSON解码与灵活类型

huangapple go评论93阅读模式
英文:

JSON decode with flexible type

问题

我需要以一种灵活的方式指定解码JSON数据的类型,这意味着类型需要在运行时指定。

考虑以下代码片段:http://play.golang.org/p/F-Jy4ufMPz

s := `{"b":[{"x":9},{"x":4}]}`

var a struct {
  B []interface{}
}
err := json.Unmarshal([]byte(s), &a)
if err != nil {
  panic(err)
}

fmt.Println(a)

这将产生{[map[x:9] map[x:4]]}。我想要解码为一个特定类型(结构体)的数组,而不是[]interface{},而且不需要在编译时指定。

有没有办法在不事先创建数组的情况下实现这一点?(返回的项数是未知的)

我目前能想到的唯一方法是稍后再次对返回的映射进行编码,并将其解码为指定的类型,这将创建不必要的处理开销。

英文:

I need to specify a type for decoding JSON data in a flexible manner, meaning the type needs to be specified at runtime.

Consider this snippet: http://play.golang.org/p/F-Jy4ufMPz

s := `{"b":[{"x":9},{"x":4}]}`

var a struct {
  B []interface{}
}
err := json.Unmarshal([]byte(s), &a)
if err != nil {
  panic(err)
}

fmt.Println(a)

Which will produce {[map[x:9] map[x:4]]}. I want to decode to an array of a specific (struct) type instead of []interface{}, without specifying it at compile time.

Is that somehow possible without creating the array up front? (the number of returned items is unknown)

The only way I can think of right now is to encode the returned maps again later, and decode them to the specified type, which would create unnecessary processing overhead.

答案1

得分: 5

如果在编译时没有指定它,你仍然需要在某个地方指定它。

如果在检索Json数据之前指定了它,你可以简单地使用switch case将其解组为所需的对象。

如果在Json数据中指定了它,你可以将"灵活"部分编组为json.RawMessage,在确定适合的结构类型后进行处理:

package main

import (
	"encoding/json"
	"fmt"
)

var s = `{"type":"structx", "data":{"x":9,"xstring":"This is structX"}}`

type JsonStruct struct {
	Type string
	Data json.RawMessage
}

type StructX struct {
	X       float64
	Xstring string
}

type StructY struct {
	Y bool
}

func main() {
	var a *JsonStruct
	err := json.Unmarshal([]byte(s), &a)
	if err != nil {
		panic(err)
	}

	switch a.Type {
	case "structx":
		// 将RawMessage部分解组为StructX
		var s *StructX
		json.Unmarshal([]byte(a.Data), &s)
		if err != nil {
			panic(err)
		}
		fmt.Println(s)
	case "structy":
		// 对structY执行相同的操作
	}
}

Playground

英文:

If not specifying it at compile time, you still need to specify it somewhere.

If specified before the retrieval of the Json data, you can simply do a switch case, Unmarshalling it to your desired object.

If specified within the Json data, you can marshal the "flexible" part into a json.RawMessage to process it after you've decided what type of struct is suitable:

package main

import (
	"encoding/json"
	"fmt"
)

var s = `{"type":"structx", "data":{"x":9,"xstring":"This is structX"}}`

type JsonStruct struct {
	Type string
	Data json.RawMessage
}

type StructX struct {
	X       float64
	Xstring string
}

type StructY struct {
	Y bool
}

func main() {
	var a *JsonStruct
	err := json.Unmarshal([]byte(s), &a)
	if err != nil {
		panic(err)
	}
	
	switch a.Type {
	case "structx":
		// We Unmashal the RawMessage part into a StructX
		var s *StructX
		json.Unmarshal([]byte(a.Data), &s)
		if err != nil {
			panic(err)
		}
		fmt.Println(s)
	case "structy":
		// Do the same but for structY
	}
}

Playground

huangapple
  • 本文由 发表于 2013年10月31日 02:53:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/19691468.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定