【问题标题】:Unmarshaling nested custom same-type JSON in Go在 Go 中解组嵌套的自定义同类型 JSON
【发布时间】:2022-02-11 05:00:54
【问题描述】:

鉴于以下 JSON

{
   "some": "value"
   "nested": {
     "some": "diffvalue",
     "nested": {
        "some": "innervalue"
     }
   }
}

大致翻译为这个结构:

type Envelope struct {
    some     string         `json:"some"`
    nested   InnerEnvelope  `json:"nested"`
}

InnerEnvelope 是:type InnerEnvelope map[string]interface{}

由于原始 JSON 的递归类型性质,在这里运行一个简单的 json.Unmarshal([]byte value, &target) 没有帮助。

我不知道内部映射将存在多深以及在哪些键下存在,因此我无法预先声明类型。

这个想法是,使用map[string]interface{} 作为类型还不够好,因为我需要以某种方式转换和键入InnerEnvelope 中的值。细节并不重要,但图像,我需要将 bool 类型的 NestedEnvelope 中的每个值转换为字符串,表示“true”或“false”,而不是实际的 bool 类型。

我转向UnmarshalJSON接口解决了这个问题。我可以像这样在顶层轻松做到这一点:

func (m *Envelope) UnmarshalJSON(b []byte) error {
    var stuff noBoolMap
    if err := json.Unmarshal(b, &stuff); err != nil {
        return err
    }
    for key, value := range stuff {
        switch value.(type) {

        case bool:
            stuff[key] = strconv.FormatBool(value.(bool))
        }
    }
    return nil
}

但由于内部 json.Unmarshal 已经将内部映射解析为 map[string]interface{},我需要再次遍历内部映射,将它们转换为适当的类型并执行我的值转换。

所以我的问题是:在这种情况下,Go 中的处理方式是什么,最好一次性完成?

上述 JSON 示例的预期结果是:

Envelope {
     some: string
     nested: InnerEnvelope {
       some: string {
       nested: InnerEnvelope {
         some: string
       }
     }
  }

【问题讨论】:

  • 简短的回答是肯定的,您需要将interface{} 转换为string 或可能另一个map[string]interface{},因为正如您所提到的,您在编译时不知道结构。
  • “我不知道前面..内部映射将存在于哪些键下,所以我不能预先声明类型。..使用 map[string]interface{} 因为类型不好够了,因为我需要以某种方式转换和输入 InnerEnvelope 中的值。”听起来你有矛盾
  • 我不明白你为什么觉得你需要一个自定义的解组方法。 Go 支持递归数据类型就好了:play.golang.org/p/v4hKMTpGSWu.
  • @Peter 澄清一下,示例应该说明nested1nested2 等等,我不会事先知道嵌套结构将在哪些键下。 @Vorsprung:你在哪里看到了矛盾?

标签: json go recursion


【解决方案1】:

鉴于您的 json,您可以这样做:

type Envelope struct {
    Some     string         `json:"some"`
    Nested   json.RawMessage  `json:"nested"`
}

json.RawMessage 是一个相当隐蔽的宝石,似乎越来越多的人选择了 map[string]interface{}。

使用 json.RawMessage 将导致嵌套 json 由 RawMessage 表示,然后您可以再次将其作为普通 json 处理(将其解组到 Envelope)。

这比 map[string]interface{} 方法更优雅。

【讨论】:

  • 我认为这已经接近我想要的了。我将如何将递归应用于此原则,即:a)解组顶级,查找 RawMessage 的内容 b)解组发现 RawMessage 字段,以便将任何可能是映射的键再次解组为 RawMessage c)执行上述任意操作深度和领域?这似乎很基本,但在我看来,我需要以某种方式定义要动态解组的类型。
  • 非常迟的响应然而:递归是可能的,只需用相同的结构解析下一个 json.RawMessage 并不断重复,直到你只剩下基本类型
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-02
  • 2013-12-11
  • 2022-01-11
相关资源
最近更新 更多