解组可能是字符串或对象的JSON

时间:2017-10-15 09:52:45

标签: json go

我有第三方服务返回JSON,其中一个字段包含数据集合。以下是它返回的结构示例。

{
  "title": "Afghanistan",
  "slug": "afghanistan",
  "fields": {
    "fieldOne": "",
    "fieldTwo": {
      "new1": {
        "type": "contentBlock",,
        "fields": {
          "richTextBlick": "<p>This is the travel advice.<\/p>"
        }
      }
    },
    "fieldThree": {
      "new1": {
        "type": "introBlock",
        "fields": {
          "text": "This is a title"
          "richText": "<p>This is the current travel summary for Afganistan.<\/p>"
        }
      },
      "new2": {
        "type": "contentBlock",
        "fields": {
          "richText": "<p>It has a second block of content!<\/p>"
        }
      }
    },
    "fieldfour": "country"
  }
}

每个“字段”条目可以是字符串或其他对象。我想将这些解码为类似下面的结构。

type EntryVersion struct {
    Slug string `json:"slug"`
    Fields map[string][]EntryVersionBlock `json:"fields"`
}

type EntryVersionBlock struct {
    Type string `json:"type"`
    Fields map[string]string `json:"fields"`
}

如果字段值只是一个字符串,我会将它包装在一个EntryVersionBlock中,其类型为“Text”,并在Fields映射中包含一个条目。

任何想法如何以有效的方式做到这一点?在极端情况下,我可能要做几百次。

由于

2 个答案:

答案 0 :(得分:4)

你的结构与json的结构略有不同。 Fields中的EntryVersion是一个不是数组的对象,因此将其作为切片并不是您想要的。我建议你改成它:

type EntryVersion struct {
    Slug   string                       `json:"slug"`
    Fields map[string]EntryVersionBlock `json:"fields"`
}

EntryVersionBlock在相应的json中没有"type"字段,其中包含字段名称为"new1""new2"等的条目。所以我建议您添加第3种类型Entry,您可以在其中解组这些字段。

type Entry struct {
    Type   string            `json:"type"`
    Fields map[string]string `json:"fields"`
}

你会更新你的EntryVersionBlock看起来像这样:

type EntryVersionBlock struct {
    Value  string           `json:"-"`
    Fields map[string]Entry `json:"fields"`
}

要处理原始问题,您可以让EntryVersionBlock类型实现json.Unmarshaler接口,检查传递给UnmarshalJSON方法的数据中的第一个字节,如果它&#39一个双引号它是一个字符串,如果它是一个卷曲的开口括号,它就是一个对象。像这样:

func (evb *EntryVersionBlock) UnmarshalJSON(data []byte) error {
    switch data[0] {
    case '"':
        if err := json.Unmarshal(data, &evb.Value); err != nil {
            return err
        }
    case '{':
        evb.Fields = make(map[string]Entry)
        if err := json.Unmarshal(data, &evb.Fields); err != nil {
            return err
        }
    }
    return nil
}

游乐场:https://play.golang.org/p/IsTXI5202m

答案 1 :(得分:0)

您可以使用GJson库来解组您的JSON以进行映射,然后在此地图上进行迭代,并使用结构并根据字段类型(地图或字符串)进行所需的转换。

更新:使用此方法的示例与类似的情况 http://blog.serverbooter.com/post/parsing-nested-json-in-go/