根据键值对解析 Golang 的 JSON。

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

Golang json unmarshal according to key value pair

问题

我有以下的JSON数据:

  1. "data": [
  2. {
  3. "id": "recent_search",
  4. "items": [],
  5. "name": ""
  6. },
  7. {
  8. "id": "popular_search",
  9. "items": [],
  10. "name": ""
  11. },
  12. {
  13. "id": "digital",
  14. "items": [],
  15. "name": "DIGITAL"
  16. }
  17. ]

结构体如下:

  1. type universeTypeData struct {
  2. Recent universeSearchInfo
  3. Popular universeSearchInfo
  4. Digital universeSearchInfo
  5. }
  6. type universeSearchInfo struct {
  7. ID string `json:"id"`
  8. Name string `json:"name"`
  9. Items []universeSearchItem `json:"items"`
  10. }

我想将JSON中的"id"为"recent_search"的部分映射到Recent,将"id"为"popular_search"的部分映射到Popular。在Golang中有没有更好的方法来实现这个?

我的做法是:

  1. for _, v := range result.Data {
  2. if v.ID == "in_category" {
  3. finalResult.Universe.InCategory.ID = v.ID
  4. finalResult.Universe.InCategory.Name = v.Name
  5. for _, abc := range v.Items {
  6. finalResult.Universe.InCategory.Items = append(finalResult.Universe.InCategory.Items, abc)
  7. }
  8. }
  9. if v.ID == "recent_search" {
  10. finalResult.Universe.Recent.ID = v.ID
  11. finalResult.Universe.Recent.Name = v.Name
  12. for _, abc := range v.Items {
  13. finalResult.Universe.Recent.Items = append(finalResult.Universe.Recent.Items, abc)
  14. }
  15. }
  16. if v.ID == "popular_search" {
  17. finalResult.Universe.Popular.ID = v.ID
  18. finalResult.Universe.Popular.Name = v.Name
  19. for _, abc := range v.Items {
  20. finalResult.Universe.Popular.Items = append(finalResult.Universe.Popular.Items, abc)
  21. }
  22. }
  23. }

有没有更好的方法来实现这个?

英文:

I have json as following

  1. "data": [
  2. {
  3. "id": "recent_search",
  4. "items": [],
  5. "name": ""
  6. },
  7. {
  8. "id": "popular_search",
  9. "items": [],
  10. "name": ""
  11. },
  12. {
  13. "id": "digital",
  14. "items": [],
  15. "name": "DIGITAL"
  16. }
  17. ]

and the structs are as follows:

  1. type universeTypeData struct {
  2. Recent universeSearchInfo
  3. Popular universeSearchInfo
  4. Digital universeSearchInfo
  5. }
  6. type universeSearchInfo struct {
  7. ID string `json:"id"`
  8. Name string `json:"name"`
  9. Items []universeSearchItem `json:"items"`
  10. }

I want to unmarshal my json as "id" with value "recent_search" map to Recent, "id" with value "popular_search" map to Popular. Is there any way of doing this in golang?

My approach of doing it is

  1. for _, v := range result.Data {
  2. if v.ID == "in_category" {
  3. finalResult.Universe.InCategory.ID = v.ID
  4. finalResult.Universe.InCategory.Name = v.Name
  5. for _, abc := range v.Items {
  6. finalResult.Universe.InCategory.Items = append(finalResult.Universe.InCategory.Items, abc)
  7. }
  8. }
  9. if v.ID == "recent_search" {
  10. finalResult.Universe.Recent.ID = v.ID
  11. finalResult.Universe.Recent.Name = v.Name
  12. for _, abc := range v.Items {
  13. finalResult.Universe.Recent.Items = append(finalResult.Universe.Recent.Items, abc)
  14. }
  15. }
  16. if v.ID == "popular_search" {
  17. finalResult.Universe.Popular.ID = v.ID
  18. finalResult.Universe.Popular.Name = v.Name
  19. for _, abc := range v.Items {
  20. finalResult.Universe.Popular.Items = append(finalResult.Universe.Popular.Items, abc)
  21. }
  22. }

Is there any better way of doing it?

答案1

得分: 2

你想将JSON数组解组成Go结构体,但它们之间没有自然映射关系。无论如何,你最好先将其解组成切片,然后再解析该切片。一种解决方法是使用json.Decoder。

  1. dec := json.NewDecoder(JSONdataReader)
  2. var res universeTypeData
  3. // 读取开括号
  4. dec.Token()
  5. // 当数组包含值时
  6. for dec.More() {
  7. var m universeSearchInfo
  8. // 解码数组值
  9. dec.Decode(&m)
  10. switch m.ID {
  11. case "recent_search":
  12. res.Recent = m
  13. case "popular_search":
  14. res.Popular = m
  15. case "digital":
  16. res.Digital = m
  17. }
  18. }
  19. // 读取闭括号
  20. dec.Token()

这样可以实现即时解码,一次通过,而不会消耗中间切片表示。这里有一个工作示例

英文:

You want to unmurshal JSON array into Go struct which is not natural mapping. Any way, you most likely should be first unmurshal in slice and then parse this slice. Some workaround is to use json.Decoder

  1. dec := json.NewDecoder(JSONdataReader)
  2. var res universeTypeData
  3. // read open bracket
  4. dec.Token()
  5. // while the array contains values
  6. for dec.More() {
  7. var m universeSearchInfo
  8. // decode an array value
  9. dec.Decode(&m)
  10. switch m.ID {
  11. case "recent_search":
  12. res.Recent = m
  13. case "popular_search":
  14. res.Popular = m
  15. case "digital":
  16. res.Digital = m
  17. }
  18. }
  19. // read closing bracket
  20. dec.Token()

which allow you to decode on the fly, in one pass, without consuming intermediate slice representation. Working example

答案2

得分: 1

实现Unmarshaler接口:

Unmarshaler是由可以将自身的JSON描述解组的类型实现的接口。输入可以假定为JSON值的有效编码。如果希望在返回后保留数据,UnmarshalJSON必须复制JSON数据。

json unmarshaler接口将从json中解析的结果分配给结构体,并应用条件来获取值。

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. )
  6. type Details struct {
  7. Data []universeSearchInfo `json:"data"`
  8. }
  9. type universeTypeData struct {
  10. Recent universeSearchInfo
  11. Popular universeSearchInfo
  12. Digital universeSearchInfo
  13. }
  14. type universeSearchInfo struct {
  15. ID string `json:"id"`
  16. Name string `json:"name"`
  17. Items []string `json:"items"`
  18. }
  19. func main() {
  20. var result universeTypeData
  21. jsonBytes := []byte(`{"data": [
  22. {
  23. "id": "recent_search",
  24. "items": [],
  25. "name": ""
  26. },
  27. {
  28. "id": "popular_search",
  29. "items": [],
  30. "name": ""
  31. },
  32. {
  33. "id": "digital",
  34. "items": [],
  35. "name": "DIGITAL"
  36. }
  37. ]}`)
  38. if err := json.Unmarshal(jsonBytes, &result); err != nil {
  39. fmt.Println(err)
  40. }
  41. fmt.Println(result)
  42. }
  43. func (universeData *universeTypeData) UnmarshalJSON(data []byte) error {
  44. var result Details
  45. if err := json.Unmarshal(data, &result); err != nil {
  46. return err
  47. }
  48. for _, value := range result.Data {
  49. switch value.ID {
  50. case "recent_search":
  51. universeData.Recent = value
  52. }
  53. }
  54. return nil
  55. }

Go Playground上的工作代码

英文:

Implement Unmarshaler interface:

> Unmarshaler is the interface implemented by types that can unmarshal a
> JSON description of themselves. The input can be assumed to be a valid
> encoding of a JSON value. UnmarshalJSON must copy the JSON data if it
> wishes to retain the data after returning.

json unmarshaler interface assign the value from json to struct after parsing the result and applying conditions to fetch the value.

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. )
  6. type Details struct {
  7. Data []universeSearchInfo `json:"data"`
  8. }
  9. type universeTypeData struct {
  10. Recent universeSearchInfo
  11. Popular universeSearchInfo
  12. Digital universeSearchInfo
  13. }
  14. type universeSearchInfo struct {
  15. ID string `json:"id"`
  16. Name string `json:"name"`
  17. Items []string `json:"items"`
  18. }
  19. func main() {
  20. var result universeTypeData
  21. jsonBytes := []byte(`{"data": [
  22. {
  23. "id": "recent_search",
  24. "items": [],
  25. "name": ""
  26. },
  27. {
  28. "id": "popular_search",
  29. "items": [],
  30. "name": ""
  31. },
  32. {
  33. "id": "digital",
  34. "items": [],
  35. "name": "DIGITAL"
  36. }
  37. ]}`)
  38. if err := json.Unmarshal(jsonBytes, &result); err != nil {
  39. fmt.Println(err)
  40. }
  41. fmt.Println(result)
  42. }
  43. func (universeData *universeTypeData) UnmarshalJSON(data []byte) error {
  44. var result Details
  45. if err := json.Unmarshal(data, &result); err != nil {
  46. return err
  47. }
  48. for _,value := range result.Data{
  49. switch value.ID {
  50. case "recent_search":
  51. universeData.Recent = value
  52. }
  53. }
  54. return nil
  55. }

Working code on Go Playground

huangapple
  • 本文由 发表于 2018年7月16日 17:39:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/51358796.html
匿名

发表评论

匿名网友

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

确定