基于参数值在Golang中解码传入的JSON数据

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

Decoding incoming JSON in Golang based on param values

问题

我正在尝试在使用Go编写的REST API中解码传入的JSON。我正在使用decoder.Decode()函数,我的问题是我需要在解码过程中应用一定的规则来确定使用哪个结构体,因为有时JSON包含以下内容:

"type": {
    "type" : "string",
    "maxLength" : 30
},

而有时候包含以下内容:

"type": {
    "type" : "integer",
    "max" : 30,
    "min" : 10
},

我需要告诉Go:“如果type.type是string,使用这个结构体(type Type_String struct),如果type.type是integer,使用另一个结构体(type Type_Integer struct)”。我不太确定该如何做。我脑海中的一个解决方案是创建一个包含所有可能属性的通用结构体,在任何类型的对象上使用它,然后根据type属性过滤属性,但这样做太混乱了。我想我也可以编写自己的解码器,但那似乎也有点奇怪。

我对Go还很陌生,我非常习惯JavaScript提供的自由度。

英文:

I am trying to decode an incoming JSON in my REST API written in Go. I am using decoder.Decode() function and my problem is that I need to apply a certain rules on which struct should be used in the process of decoding because sometimes the JSON contains:

"type": {
    "type" : "string",
    "maxLength" : 30
},

and sometimes:

"type": {
    "type" : "integer",
    "max" : 30,
    "min" : 10
},

I somehow need to tell Go that "If the type.type is string, use this struct (type Type_String struct) and if the type.type is integer, use other struct (type Type_Integer struct)". I am not really sure how to do it. One solution which is on my mind is to make an universal struct with the all possible properties, use it on any kind of object and then filter the properties based on the type property but this is just so dirty. I guess I can also write my own decoder but that seems also a bit strange.

I am new to Go and I am pretty much used to the freedom JavaScript offers.

答案1

得分: 1

首先,如果"type"字段取决于"type.type"字段,我认为最好将其提升一个级别。类似于:

...
"type" : "integer",
"intOptions": {
    "max" : 30,
    "min" : 10
},
....

然后,您可以创建一个只有一个字段的结构体:

type Type struct {
	Type string
}

然后可以进行如下操作:

myType := new(Type)
json.Unmarshal([]byte(yourJsonString), myType)

现在,根据myType的值,您可以使用不同的结构体来解码您的json数据。

英文:

First of all, if fields of "type" depends on "type.type", in my opinion, it's better to move it one level up. Something like:

...
"type" : "integer",
"intOptions": {
    "max" : 30,
    "min" : 10
},
....

Then you can create a struct with only one field:

type Type struct {
	Type string
}

and do something like:

myType := new(Type)
json.Unmarshal([]byte(yourJsonString), myType)

And now, depending on myType's value you can use different structs for decoding your json.

答案2

得分: 0

你可以始终将其解码为interface{},就像这里提到的那样:https://stackoverflow.com/questions/23577193/how-to-access-interface-fields-on-json-decode

http://play.golang.org/p/3z8-unhsH4

package main

import (
	"encoding/json"
	"fmt"
)

var one string = `{"type": {"type": "string", "maxLength":30}}`
var two string = `{"type": {"type": "integer", "max":30, "min":10}}`

func f(data map[string]interface{}) {
	t := data["type"]
	typemap := t.(map[string]interface{})
	t2 := typemap["type"].(string)
	switch t2 {
	case "string":
		fmt.Println("maxlength:", typemap["maxLength"].(float64))
	case "integer":

		fmt.Println("max:", typemap["max"].(float64))
	default:
		panic("oh no!")
	}
}

func main() {
	var jsonR map[string]interface{}
	err := json.Unmarshal([]byte(one), &jsonR)
	if err != nil {
		panic(err)
	}
	f(jsonR)
	json.Unmarshal([]byte(two), &jsonR)
	f(jsonR)
}

这个想法是将其解组为map[string]interface{},然后进行类型转换和比较,然后再访问值。

在上面的代码中,函数f执行了类型转换和比较。给定这个糟糕的JSON,我使用了糟糕的变量名t和t2来表示不同深度的"type"的JSON值。一旦t2有了值,switch语句就会根据"string"或"integer"做一些操作,并打印出maxLength或max值。

英文:

You can always decode to interface{} like mentioned here: https://stackoverflow.com/questions/23577193/how-to-access-interface-fields-on-json-decode

http://play.golang.org/p/3z8-unhsH4

package main

import (
	"encoding/json"
	"fmt"
)

var one string = `{"type": {"type": "string", "maxLength":30}}`
var two string = `{"type": {"type": "integer", "max":30, "min":10}}`

func f(data map[string]interface{}) {
	t := data["type"]
	typemap := t.(map[string]interface{})
	t2 := typemap["type"].(string)
	switch t2 {
	case "string":
		fmt.Println("maxlength:", typemap["maxLength"].(float64))
	case "integer":

		fmt.Println("max:", typemap["max"].(float64))
	default:
		panic("oh no!")
	}
}

func main() {
	var jsonR map[string]interface{}
	err := json.Unmarshal([]byte(one), &jsonR)
	if err != nil {
		panic(err)
	}
	f(jsonR)
	json.Unmarshal([]byte(two), &jsonR)
	f(jsonR)
}

The idea is to unmarshal to map[string]interface{} and then cast and compare before accessing values.

In the above code, the f function does the cast and compare. Given this poor json, I used poor variable name, t and t2 to represent the json values of "type" at different depths. Once t2 has the value, the switch statement does something with the "string" or the "integer" and what it does is print the maxLength or the max value.

huangapple
  • 本文由 发表于 2014年12月25日 08:32:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/27643341.html
匿名

发表评论

匿名网友

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

确定