英文:
Convert json with variable types to strings
问题
我正在从API响应中读取JSON,并遇到一个问题,即JSON值内部有多种数据类型(字符串、null、布尔值)。此外,一些键的值可以是字符串或null,这使得将数据读入类型更加困难。我想将所有内容转换为字符串以便于处理。我根据搜索到的其他示例创建了一个基于类型的转换开关。我想知道这是否是最简单的方法,或者是否有更简单的方法。
package main
import (
"encoding/json"
"fmt"
"strconv"
)
func main() {
json_byte := []byte(`{"response":[{"t_int":1, "t_bool": true, "t_null_or_string": null}, {"t_int":2, "t_bool": false, "t_null_or_string": "string1"}]}`)
//unmarshal the json to data structure using interface for variable data types
data_json := make(map[string][]map[string]interface{}) //create a structure to hold unmarshalled json
if err := json.Unmarshal(json_byte, &data_json); err != nil {
panic(err)
}
fmt.Println("json_data: ", data_json)
//Iterate over data structure and convert Bool, Int, and Null types to string
var v_conv string // temporary holding for converted string values
data_map := make(map[string]string) // temporary holding for converted maps
data_final := make([]map[string]string, 0, 100) // final holding for data converted to strings
for _, v := range data_json { //v is the value of the "response": key which is a slice of maps
for _, v2 := range v { //v2 is one of the maps in the slice of maps
for k3, v3 := range v2 { //k3 and v3 are the keys and values inside the map
fmt.Println("k3: ", k3, "v3: ", v3)
switch v_type := v3.(type) {
case nil:
v_conv = ""
case bool:
v_conv = strconv.FormatBool(v3.(bool))
case int:
v_conv = strconv.Itoa(v3.(int))
case string:
v_conv = v3.(string)
case float64:
v_conv = strconv.FormatFloat(v3.(float64), 'f', 0, 64)
default:
fmt.Println("vtype unknown: ", v_type) //have to use v_type since it is declared
v_conv = ""
}
data_map[k3] = v_conv //append a new map key/value pair both as strings
fmt.Println("data_map: ", data_map)
}
data_final = append(data_final, data_map) // after each cycle through the loop append the map to the new list
fmt.Println("data_final: ", data_final)
}
}
}
期望的最终格式是一个映射的切片:
[{
"t_int": "1",
"t_bool": "true",
"t_null_string": ""
},
{
"t_int": "2",
"t_bool": "false",
"t_null_string": "string1"
}]
英文:
I am reading in json from an API response and I ran into an issue in that there are multiple data types inside the json values (strings, null, bool). In addition, some keys have values which can be either a string or null which makes reading the data into types more difficult. I want to convert everything to strings for ease of handling. I created a type switch based on googling other examples. I am wondering if this is the easiest way to do this or if I am missing a simpler approach.
package main
import (
"encoding/json"
"fmt"
"strconv"
)
func main() {
json_byte := []byte(`{"response":[{"t_int":1, "t_bool": true, "t_null_or_string": null}, {"t_int":2, "t_bool": false, "t_null_or_string": "string1"}]}`)
//unmarshal the json to data structure using interface for variable data types
data_json := make(map[string][]map[string]interface{}) //create a structure to hold unmarshalled json
if err := json.Unmarshal(json_byte, &data_json); err != nil {
panic(err)
}
fmt.Println("json_data: ", data_json)
//Iterate over data structure and convert Bool, Int, and Null types to string
var v_conv string // temporary holding for converted string values
data_map := make(map[string]string) // temporary holding for converted maps
data_final := make([]map[string]string, 0, 100) // final holding for data converted to strings
for _, v := range data_json { //v is the value of the "response": key which is a slice of maps
for _, v2 := range v { //v2 is one of the maps in the slice of maps
for k3, v3 := range v2 { //k3 and v3 are the keys and values inside the map
fmt.Println("k3: ", k3, "v3: ", v3)
switch v_type := v3.(type) {
case nil:
v_conv = ""
case bool:
v_conv = strconv.FormatBool(v3.(bool))
case int:
v_conv = strconv.Itoa(v3.(int))
case string:
v_conv = v3.(string)
case float64:
v_conv = strconv.FormatFloat(v3.(float64), 'f', 0, 64)
default:
fmt.Println("vtype unknown: ", v_type) //have to use v_type since it is declared
v_conv = ""
}
data_map[k3] = v_conv //append a new map key/value pair both as strings
fmt.Println("data_map: ", data_map)
}
data_final = append(data_final, data_map) // after each cycle through the loop append the map to the new list
fmt.Println("data_final: ", data_final)
}
}
}
Final Format Desired a Slice of Maps
[{
"t_int": "1",
"t_bool": "true",
"t_null_string": ""
},
{
"t_int": "2",
"t_bool": "false",
"t_null_string": "string1"
}]
答案1
得分: 2
对于这个答案,我假设你的示例中的 JSON 是你的 JSON 输入的一部分(或者是示例)。
在这种情况下,你的 JSON 具有特定的结构:你知道哪些属性具有已知的数据类型,也知道哪些属性是动态的。
例如,你可以将你的 JSON 反序列化为类似下面的 ResponseObj:
package main
import (
"encoding/json"
"fmt"
)
type ResponseObj struct {
Response []Item `json:"response"`
}
type Item struct {
TInt int `json:"t_int"`
TBool bool `json:"t_bool"`
TMixed interface{} `json:"t_null_or_string"`
}
func main() {
json_byte := []byte(`{"response":[{"t_int":1, "t_bool": true, "t_null_or_string": null}, {"t_int":2, "t_bool": false, "t_null_or_string": "string1"}]}`)
data_json := ResponseObj{}
if err := json.Unmarshal(json_byte, &data_json); err != nil {
panic(err)
}
fmt.Printf("%+v\n", data_json)
}
你的数据将会是这样的:
{
Response:
[
{
TInt:1
TBool:true
TMixed:<nil>
},
{
TInt:2
TBool:false
TMixed:string1
}
]
}
是的,对于具有混合类型的属性,你将会进行类型断言(或者像你的情况一样与 nil 进行比较,或者两者都有)。
不太可能你的 JSON 是一个完全混乱的、不可预测的类型。很可能,你可以单独提取出一个“核心”结构,并对剩余的混合类型使用 interface{}。
希望对你有所帮助。
英文:
For this answer I'm assuming that JSON in your example is an example of (part of) your JSON input.
In this case, your JSON has a specific structure: you know which attributes are coming with a known data type and also you know which attributes a dynamic.
For example, you could unmarshal your JSON into smth like ResponseObj below:
package main
import (
"encoding/json"
"fmt"
)
type ResponseObj struct {
Response []Item `json:"response"`
}
type Item struct {
TInt int `json:"t_int"`
TBool bool `json:"t_bool"`
TMixed interface{} `json:"t_null_or_string"`
}
func main() {
json_byte := []byte(`{"response":[{"t_int":1, "t_bool": true, "t_null_or_string": null}, {"t_int":2, "t_bool": false, "t_null_or_string": "string1"}]}`)
data_json := ResponseObj{}
if err := json.Unmarshal(json_byte, &data_json); err != nil {
panic(err)
}
fmt.Printf("%+v\n", data_json)
}
Your data will look like:
{
Response:
[
{
TInt:1
TBool:true
TMixed:<nil>
}
{
TInt:2
TBool:false
TMixed:string1
}
]
}
And yes, for an attribute with a mixed type you'll run a type assertion (or comparison with nil as in your case or both).
Unlikely your JSON is a total chaos of unpredictable types. Most likely, you can single out a core structure and use interface{} for remaining, mixed types.
Hope this helps.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论