在不知道结构的情况下解组嵌套的json [英] unmarshal nested json without knowing structure

查看:109
本文介绍了在不知道结构的情况下解组嵌套的json的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用密钥值存储作为golang应用程序的后端,日期用作密钥(以保持条目的排序),而json文档作为值.我要存储的每个json文档中都存在json(foo)以及typedate的顶级名称空间,但是存在一些差异(尤其是对于某些嵌套的json数据),因此当从数据库中提取密钥时,我真的不知道在遍历的任何时候我要提取什么.这是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答案

但是,与那个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`
}

两部分问题:

  1. 有没有一种方法可以避免重复的编组(或者是我什至不关心的事情)
  2. 如何确定将json.RawMessage解组到哪个结构(它也允许嵌套的json数据)

更新:@chendesheng提供的初始答案使我能够找到类型,但是一旦确定了类型(我需要这样做),就不必再次将其解组为结构在对他/她的答案发表评论时,我会对这两种可能性中的任何一种感兴趣

a)制作一个json.RawMessage的副本,按您显示的方式解编入接口(通过chendesheng的答案),然后在您知道类型后将其解组到struct的副本(从解组到接口后)? /p>

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

解决方案

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

  1. 将json.RawMessage解组到地图[string]接口{}
  2. 使用正则表达式提取字符串类型

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

I am using a key value store as the backend for my golang application, with the date serving as the key (to keep entries sorted) and json documents as the values. The top level namespace of the json (foo) and the type and date are present in each json document that I'm storing but otherwise there are some differences (especially with respect to some nested json data), so when keyI'm pulling from the database, I don't really know what I'm pulling out at any time that I'm looping through . Here is a sample of the json data

{
  "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"
  }
}


when I'm pulling from the database, the first thing I do is unmarshal each entry into a map[string]*json.RawMessage to deal with the foo namespace

//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
   }

which I do thanks to this SO answer

However, unlike in that SO answer, when I have to unmarshal again whatever is contained under the foo namespace I don't know which struct to unmarshal into

   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`
}

Two part Question:

  1. Is there a way to avoid repeated unmarshals (or is that something I shouldn't even care about)
  2. how can I figure out which struct to unmarshal the json.RawMessage into (which also allows for nested json data)

Update: the initial answer provided by @chendesheng enables me to find out the type but not to unmarshal again into a struct once that type has been determined (which I need to do), so based on a conversation in the comments to his/her answer, I would be interested in either of these possibilities

a) make a copy of the json.RawMessage, unmarshal into the interface as you shown (by chendesheng's answer), and then unmarshal the copy itno the struct once you know the type (from having unmarshaled into the interface)?

b) use a regular expression to determine the type and then unmarshal into a struct of that type once it's known

解决方案

Two ways to check struct type:

  1. Unmarshal json.RawMessage to a map[string]interface{}
  2. Use a regular expression to extract type string

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

这篇关于在不知道结构的情况下解组嵌套的json的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆