根据键值对解析 Golang 的 JSON。

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

Golang json unmarshal according to key value pair

问题

我有以下的JSON数据:

"data": [
    {
        "id": "recent_search",
        "items": [],
        "name": ""
    },
    {
        "id": "popular_search",
        "items": [],
        "name": ""
    },
    {
        "id": "digital",
        "items": [],
        "name": "DIGITAL"
    }
]

结构体如下:

type universeTypeData struct {
    Recent  universeSearchInfo
    Popular universeSearchInfo
    Digital universeSearchInfo
}

type universeSearchInfo struct {
    ID    string               `json:"id"`
    Name  string               `json:"name"`
    Items []universeSearchItem `json:"items"`
}

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

我的做法是:

for _, v := range result.Data {
    if v.ID == "in_category" {
        finalResult.Universe.InCategory.ID = v.ID
        finalResult.Universe.InCategory.Name = v.Name
        for _, abc := range v.Items {
            finalResult.Universe.InCategory.Items = append(finalResult.Universe.InCategory.Items, abc)
        }
    }
    if v.ID == "recent_search" {
        finalResult.Universe.Recent.ID = v.ID
        finalResult.Universe.Recent.Name = v.Name
        for _, abc := range v.Items {
            finalResult.Universe.Recent.Items = append(finalResult.Universe.Recent.Items, abc)
        }
    }
    if v.ID == "popular_search" {
        finalResult.Universe.Popular.ID = v.ID
        finalResult.Universe.Popular.Name = v.Name
        for _, abc := range v.Items {
            finalResult.Universe.Popular.Items = append(finalResult.Universe.Popular.Items, abc)
        }
    }
}

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

英文:

I have json as following

"data": [
    {
        "id": "recent_search",
        "items": [],
        "name": ""
    },
    {
        "id": "popular_search",
        "items": [],
        "name": ""
    },
    {
        "id": "digital",
        "items": [],
        "name": "DIGITAL"
    }
]

and the structs are as follows:

type universeTypeData struct {
Recent       universeSearchInfo 
Popular      universeSearchInfo 
Digital      universeSearchInfo 
}

type universeSearchInfo struct {
ID    string               `json:"id"`
Name  string               `json:"name"`
Items []universeSearchItem `json:"items"`
}

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

for _, v := range result.Data {
	if v.ID == "in_category" {
		finalResult.Universe.InCategory.ID = v.ID
		finalResult.Universe.InCategory.Name = v.Name
		for _, abc := range v.Items {
			finalResult.Universe.InCategory.Items = append(finalResult.Universe.InCategory.Items, abc)
		}
	}
	if v.ID == "recent_search" {
		finalResult.Universe.Recent.ID = v.ID
		finalResult.Universe.Recent.Name = v.Name
		for _, abc := range v.Items {
			finalResult.Universe.Recent.Items = append(finalResult.Universe.Recent.Items, abc)
		}
	}
	if v.ID == "popular_search" {
		finalResult.Universe.Popular.ID = v.ID
		finalResult.Universe.Popular.Name = v.Name
		for _, abc := range v.Items {
			finalResult.Universe.Popular.Items = append(finalResult.Universe.Popular.Items, abc)
		}
	}

Is there any better way of doing it?

答案1

得分: 2

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

dec := json.NewDecoder(JSONdataReader)
var res universeTypeData
// 读取开括号
dec.Token()
// 当数组包含值时
for dec.More() {
    var m universeSearchInfo
    // 解码数组值
    dec.Decode(&m)
    switch m.ID {
    case "recent_search":
        res.Recent = m
    case "popular_search":
        res.Popular = m
    case "digital":
        res.Digital = m
    }
}
// 读取闭括号
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

dec := json.NewDecoder(JSONdataReader)
var res universeTypeData
// read open bracket
dec.Token()
// while the array contains values
for dec.More() {
	var m universeSearchInfo
	// decode an array value
	dec.Decode(&m)
	switch m.ID {
	case "recent_search":
		res.Recent = m
	case "popular_search":
		res.Popular = m
	case "digital":
		res.Digital = m
	}
}
// read closing bracket
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中解析的结果分配给结构体,并应用条件来获取值。

package main

import (
	"encoding/json"
	"fmt"
)

type Details struct {
	Data []universeSearchInfo `json:"data"`
}

type universeTypeData struct {
	Recent  universeSearchInfo
	Popular universeSearchInfo
	Digital universeSearchInfo
}

type universeSearchInfo struct {
	ID    string   `json:"id"`
	Name  string   `json:"name"`
	Items []string `json:"items"`
}

func main() {
	var result universeTypeData
	jsonBytes := []byte(`{"data": [
					{
						"id": "recent_search",
						"items": [],
						"name": ""
					},
					{
						"id": "popular_search",
						"items": [],
						"name": ""
					},
					{
						"id": "digital",
						"items": [],
						"name": "DIGITAL"
					}
				]}`)
	if err := json.Unmarshal(jsonBytes, &result); err != nil {
		fmt.Println(err)
	}
	fmt.Println(result)

}

func (universeData *universeTypeData) UnmarshalJSON(data []byte) error {
	var result Details
	if err := json.Unmarshal(data, &result); err != nil {
		return err
	}
	for _, value := range result.Data {
		switch value.ID {
		case "recent_search":
			universeData.Recent = value
		}
	}
	return nil
}

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.

package main
import (
"encoding/json"
"fmt"
)
type Details struct {
Data []universeSearchInfo `json:"data"`
}
type universeTypeData struct {
Recent  universeSearchInfo
Popular universeSearchInfo
Digital universeSearchInfo
}
type universeSearchInfo struct {
ID    string   `json:"id"`
Name  string   `json:"name"`
Items []string `json:"items"`
}
func main() {
var result universeTypeData
jsonBytes := []byte(`{"data": [
{
"id": "recent_search",
"items": [],
"name": ""
},
{
"id": "popular_search",
"items": [],
"name": ""
},
{
"id": "digital",
"items": [],
"name": "DIGITAL"
}
]}`)
if err := json.Unmarshal(jsonBytes, &result); err != nil {
fmt.Println(err)
}
fmt.Println(result)
}
func (universeData *universeTypeData) UnmarshalJSON(data []byte) error {
var result Details
if err := json.Unmarshal(data, &result); err != nil {
return err
}
for _,value := range result.Data{
switch value.ID {
case "recent_search":
universeData.Recent = value
}
}
return nil
}

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:

确定