将包含变量类型的 JSON 转换为字符串。

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

Convert json with variable types to strings

问题

我正在从API响应中读取JSON,并遇到一个问题,即JSON值内部有多种数据类型(字符串、null、布尔值)。此外,一些键的值可以是字符串或null,这使得将数据读入类型更加困难。我想将所有内容转换为字符串以便于处理。我根据搜索到的其他示例创建了一个基于类型的转换开关。我想知道这是否是最简单的方法,或者是否有更简单的方法。

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "strconv"
  6. )
  7. func main() {
  8. 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"}]}`)
  9. //unmarshal the json to data structure using interface for variable data types
  10. data_json := make(map[string][]map[string]interface{}) //create a structure to hold unmarshalled json
  11. if err := json.Unmarshal(json_byte, &data_json); err != nil {
  12. panic(err)
  13. }
  14. fmt.Println("json_data: ", data_json)
  15. //Iterate over data structure and convert Bool, Int, and Null types to string
  16. var v_conv string // temporary holding for converted string values
  17. data_map := make(map[string]string) // temporary holding for converted maps
  18. data_final := make([]map[string]string, 0, 100) // final holding for data converted to strings
  19. for _, v := range data_json { //v is the value of the "response": key which is a slice of maps
  20. for _, v2 := range v { //v2 is one of the maps in the slice of maps
  21. for k3, v3 := range v2 { //k3 and v3 are the keys and values inside the map
  22. fmt.Println("k3: ", k3, "v3: ", v3)
  23. switch v_type := v3.(type) {
  24. case nil:
  25. v_conv = ""
  26. case bool:
  27. v_conv = strconv.FormatBool(v3.(bool))
  28. case int:
  29. v_conv = strconv.Itoa(v3.(int))
  30. case string:
  31. v_conv = v3.(string)
  32. case float64:
  33. v_conv = strconv.FormatFloat(v3.(float64), 'f', 0, 64)
  34. default:
  35. fmt.Println("vtype unknown: ", v_type) //have to use v_type since it is declared
  36. v_conv = ""
  37. }
  38. data_map[k3] = v_conv //append a new map key/value pair both as strings
  39. fmt.Println("data_map: ", data_map)
  40. }
  41. data_final = append(data_final, data_map) // after each cycle through the loop append the map to the new list
  42. fmt.Println("data_final: ", data_final)
  43. }
  44. }
  45. }

期望的最终格式是一个映射的切片:

  1. [{
  2. "t_int": "1",
  3. "t_bool": "true",
  4. "t_null_string": ""
  5. },
  6. {
  7. "t_int": "2",
  8. "t_bool": "false",
  9. "t_null_string": "string1"
  10. }]
英文:

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.

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "strconv"
  6. )
  7. func main() {
  8. 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"}]}`)
  9. //unmarshal the json to data structure using interface for variable data types
  10. data_json := make(map[string][]map[string]interface{}) //create a structure to hold unmarshalled json
  11. if err := json.Unmarshal(json_byte, &data_json); err != nil {
  12. panic(err)
  13. }
  14. fmt.Println("json_data: ", data_json)
  15. //Iterate over data structure and convert Bool, Int, and Null types to string
  16. var v_conv string // temporary holding for converted string values
  17. data_map := make(map[string]string) // temporary holding for converted maps
  18. data_final := make([]map[string]string, 0, 100) // final holding for data converted to strings
  19. for _, v := range data_json { //v is the value of the "response": key which is a slice of maps
  20. for _, v2 := range v { //v2 is one of the maps in the slice of maps
  21. for k3, v3 := range v2 { //k3 and v3 are the keys and values inside the map
  22. fmt.Println("k3: ", k3, "v3: ", v3)
  23. switch v_type := v3.(type) {
  24. case nil:
  25. v_conv = ""
  26. case bool:
  27. v_conv = strconv.FormatBool(v3.(bool))
  28. case int:
  29. v_conv = strconv.Itoa(v3.(int))
  30. case string:
  31. v_conv = v3.(string)
  32. case float64:
  33. v_conv = strconv.FormatFloat(v3.(float64), 'f', 0, 64)
  34. default:
  35. fmt.Println("vtype unknown: ", v_type) //have to use v_type since it is declared
  36. v_conv = ""
  37. }
  38. data_map[k3] = v_conv //append a new map key/value pair both as strings
  39. fmt.Println("data_map: ", data_map)
  40. }
  41. data_final = append(data_final, data_map) // after each cycle through the loop append the map to the new list
  42. fmt.Println("data_final: ", data_final)
  43. }
  44. }
  45. }

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:

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. )
  6. type ResponseObj struct {
  7. Response []Item `json:"response"`
  8. }
  9. type Item struct {
  10. TInt int `json:"t_int"`
  11. TBool bool `json:"t_bool"`
  12. TMixed interface{} `json:"t_null_or_string"`
  13. }
  14. func main() {
  15. 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"}]}`)
  16. data_json := ResponseObj{}
  17. if err := json.Unmarshal(json_byte, &data_json); err != nil {
  18. panic(err)
  19. }
  20. fmt.Printf("%+v\n", data_json)
  21. }

你的数据将会是这样的:

  1. {
  2. Response:
  3. [
  4. {
  5. TInt:1
  6. TBool:true
  7. TMixed:<nil>
  8. },
  9. {
  10. TInt:2
  11. TBool:false
  12. TMixed:string1
  13. }
  14. ]
  15. }

是的,对于具有混合类型的属性,你将会进行类型断言(或者像你的情况一样与 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:

  1. package main
  2. import (
  3. &quot;encoding/json&quot;
  4. &quot;fmt&quot;
  5. )
  6. type ResponseObj struct {
  7. Response []Item `json:&quot;response&quot;`
  8. }
  9. type Item struct {
  10. TInt int `json:&quot;t_int&quot;`
  11. TBool bool `json:&quot;t_bool&quot;`
  12. TMixed interface{} `json:&quot;t_null_or_string&quot;`
  13. }
  14. func main() {
  15. json_byte := []byte(`{&quot;response&quot;:[{&quot;t_int&quot;:1, &quot;t_bool&quot;: true, &quot;t_null_or_string&quot;: null}, {&quot;t_int&quot;:2, &quot;t_bool&quot;: false, &quot;t_null_or_string&quot;: &quot;string1&quot;}]}`)
  16. data_json := ResponseObj{}
  17. if err := json.Unmarshal(json_byte, &amp;data_json); err != nil {
  18. panic(err)
  19. }
  20. fmt.Printf(&quot;%+v\n&quot;, data_json)
  21. }

Your data will look like:

  1. {
  2. Response:
  3. [
  4. {
  5. TInt:1
  6. TBool:true
  7. TMixed:&lt;nil&gt;
  8. }
  9. {
  10. TInt:2
  11. TBool:false
  12. TMixed:string1
  13. }
  14. ]
  15. }

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.

huangapple
  • 本文由 发表于 2016年12月6日 13:10:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/40988252.html
匿名

发表评论

匿名网友

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

确定