How to unmarshal dynamic json objects with Golang

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

How to unmarshal dynamic json objects with Golang

问题

让我先告诉你,我在Go世界中还是相对新手。

我想做的是读取我从一个JSON API(我无法控制)获取的JSON数据。一切都运行良好,我可以显示接收到的ID和标签。但是,fields字段有点不同,因为它是一个动态数组。

我可以从API接收到这样的数据:

{
    "id":"M7DHM98AD2-32E3223F",
    "tags": [
        {
            "id":"9M23X2Z0",
            "name":"History"
        },
        {
            "id":"123123123",
            "name":"Theory"
        }
    ],
    "fields": {
        "title":"项目标题",
        "description":"项目描述"
    }
}

或者,我可能只接收到description而没有title,或者接收到另一个随机对象,比如long_title。返回的对象可能完全不同,并且可以是无限多种可能的对象。但它们总是返回一个带有键和字符串内容的对象,就像示例中的那样。

这是我目前的代码:

type Item struct {
    ID string `json:"id"`
    Tags []Tag `json:"tags"`
    //Fields []Field `json:"fields"`
}

// 调用返回的标签数据
type Tag struct {
    ID string `json:"id"`
    Name string `json:"name"`
}

// AllEntries 从会话中获取所有条目
func AllEntries() {
    resp, _ := client.Get(APIURL)
    body, _ := ioutil.ReadAll(resp.Body)

    item := new(Item)
    _ = json.Unmarshal(body, &item)

    fmt.Println(i, "->", item.ID)
}

所以Item.Fields是动态的,无法预测将是什么键名,因此据我所知,无法为其创建一个结构体。但是,我对Go还是相当新手,有人能给我一些建议吗?谢谢

英文:

let me start by telling that I'm pretty recent in the Go world.

What I'm trying to do is to read the json I get from a JSON API (I don't control). Everything is working fine, I can show the received ID and Tags too. But the fields field is a little bit different, because its a dynamic array.

I can receive from the api this:

{
    "id":"M7DHM98AD2-32E3223F",
    "tags": [
        {
            "id":"9M23X2Z0",
            "name":"History"
        },
        {
            "id":"123123123",
            "name":"Theory"
        }
    ],
    "fields": {
        "title":"Title of the item",
        "description":"Description of the item"
    }
}

Or instead of title and description I could receive only description, or receive another random object like long_title. The objects return may differ completly and can be an infinite possibility of objects. But it always returns objects with a key and a string content like in the example.

This is my code so far:

type Item struct {
	ID string `json:"id"`
    Tags []Tag `json:"tags"`
	//Fields []Field `json:"fields"`
}

// Tag data from the call
type Tag struct {
	ID string `json:"id"`
	Name string `json:"name"`
}

// AllEntries gets all entries from the session
func AllEntries() {
	resp, _ := client.Get(APIURL)
	body, _ := ioutil.ReadAll(resp.Body)

	item := new(Item)
	_ = json.Unmarshal(body, &item)

	fmt.Println(i, "->", item.ID)
}

So the Item.Fields is dynamic, there is no way to predict what will be the key names, and therefore as far I can tell, there is no way to create a struct for it. But again, I'm pretty newbie with Go, could someone give me any tips? Thanks

答案1

得分: 7

如果"fields"中的数据始终是一个平面字典,那么可以将Fields的类型设置为map[string]string


对于任意数据,请将Fields指定为RawMessage类型,并根据其内容稍后进行解析。文档中的示例:https://play.golang.org/p/IR1_O87SHv

如果字段的变化太不可预测,那么可以保持该字段为[]byte,或者如果有一些字段始终是常见的,那么可以解析这些字段并忽略其他字段(但这将导致丢失其他字段中的数据)。

英文:

If the data in "fields" is always going to be a flat-dict then you can use map[string]string as type for the Fields.


For arbitrary data specify Fields as a RawMessage type and parse it later on based on its content. Example from docs: https://play.golang.org/p/IR1_O87SHv

If the fields are way too unpredictable then you can keep this field as is([]byte) or if there are fields that are always going to common then you can parse those and leave the rest(but this would result in loss of data present in other fields).

huangapple
  • 本文由 发表于 2016年12月29日 02:19:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/41367609.html
匿名

发表评论

匿名网友

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

确定