在不知道结构的情况下解组嵌套的 json

Posted

技术标签:

【中文标题】在不知道结构的情况下解组嵌套的 json【英文标题】:unmarshal nested json without knowing structure 【发布时间】:2015-08-14 22:28:13 【问题描述】:

我使用键值存储作为我的 golang 应用程序的后端,日期作为键(以保持条目排序),json 文档作为值。我存储的每个 json 文档中都存在 json (foo) 和 typedate 的***命名空间,但在其他方面存在一些差异(尤其是对于一些嵌套的 json 数据),所以当我从数据库中提取 key 时,我真的不知道我在循环时要提取什么。这是json数据的示例


  "foo": 
    "id": "124",
    "type": "baz",
    "rawdata": [
      123,
      345,
      345
    ],
    "epoch": "1433120656704"
  



  "foo": 
    "id": "234",
    "type": "bar",
    "rawdata": [
      
        "key": "dog",
        "values": [
          123,
          234
        ]
      ,
      
        "key": "cat",
        "values": [
          23,
          45
        ]
      
    ],
    "epoch": "1433120656705"
  



当我从数据库中提取数据时,我要做的第一件事是将每个条目解组到 map[string]*json.RawMessage 以处理 foo 命名空间

//as I'm looping through the entries in the database
   var objmap map[string]*json.RawMessage
   if err := json.Unmarshal(dbvalue, &objmap); err !=nil
       return err
   

感谢SO answer

但是,与那个 SO 答案不同,当我必须再次解组 foo 命名空间下包含的任何内容时,我不知道要解组到哪个结构

   if err :=json.Unmarshal(*objmap["foo"], &bazorbar; err != nil
         return err
   

 type Baz struct
  Id string `json:"id"`
  Type string `json:"type"`
  RawData []int `json:"rawdata"`
  Epoch string  `json:"epoch"`


type Bar struct
  Id string `json:"id"`
  Type string `json:"type"`
  RawData []*Qux `json:"rawdata"`
  Epoch string  `json:"epoch"`

//nested inside Bar
type Qux struct
  Key string `json:"key"`
  Values []int `json:"values`

两部分问题:

    有没有办法避免重复解组(或者这是我什至不应该关心的事情) 如何确定将 json.RawMessage 解组到哪个结构(也允许嵌套 json 数据)

更新:@chendesheng 提供的初始答案使我能够找出类型,但一旦确定类型(我需要这样做)就不会再次解组到结构中,因此基于在 cmets 对他/她的回答进行对话时,我会对这些可能性中的任何一种都感兴趣

a) 复制 json.RawMessage,按照您显示的方式解组到接口中(通过 chendesheng 的回答),然后在知道类型后解组该结构的副本(从解组到接口中)?

b) 使用正则表达式来确定类型,然后在知道该类型后将其解组为该类型的结构

【问题讨论】:

无意冒犯,但我认为你应该重新考虑你的设计,因为你应该能够避免在运行时做出这样的决定,或者至少使用某种类型标志来避免这种更松散的内省决定如何反序列化的方法。您将您的数据库中的数据视为来自某些无法控制和不可预测的第三方,我不建议这样做。 @evanmcdonnal 感谢您的意见。我会考虑到这一点,如果我找到更好的方法来做到这一点,我会的,但是,我不相信我将 t 视为来自不可预测的第三方。只是 json 文档的结构不一样,因此必须解组为不同的结构,因此在选择要解组的结构之前,我必须弄清楚 json 的样子 是的,json 代表不同的类型。您也可以将类型信息存储在数据库中,并使用它对调用 Unmarshal 之前的类型做出 100% 的决定性决定,您使用 unmarshal 就像它是 try/catch 一样,而不是使用 type info + select to解组为正确的类型,没有不确定的运行时行为。 【参考方案1】:

两种检查结构类型的方法:

    将 json.RawMessage 解组到 map[string]interface 使用正则表达式提取类型字符串

http://play.golang.org/p/gfP6P4SmaC

【讨论】:

我对这个答案很感兴趣,但我认为你误解了我的数据结构。我的每个文档都有一个“foo”字段(它是每个 json 文档的***命名空间)。我需要确定的是第二次解组时类型字段的值。你能重做你的 play.golang.org 来给我看吗? 但是在我将它解组到接口中之后(并弄清楚 type 字段的值是什么),我不能再次将它解组到 Bar 结构中(现在我知道 Bar 结构将是适当的结构),可以吗?我需要能够将文档放入适当的结构中 是否可以制作 json.RawMessage 的副本,如您所展示的那样解组到界面中,然后在知道类型后将副本解组到结构中? 可以,但是您可以随时通过正则表达式检查对象类型,无需解组到接口中。我建议的是处理动态 json 类型的方式。 好的,你能更新你的答案来展示如何做到这两点吗?我给了你一个赞成票,如果你能告诉我,我会接受你的回答。非常感谢您的帮助。

以上是关于在不知道结构的情况下解组嵌套的 json的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法在不创建***结构的情况下将 JSON 解码为结构

GOLANG 解组动态 JSON

golang中的动态嵌套结构

在 Golang 中将字符串解组为类似结构的结构

json解组嵌入式结构

当 JSON 字段键是日期时,如何将 JSON 对象解组为 Golang 结构?