给出以下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
中的值进行某种转换和键入。细节并不重要,但是图像,我需要将布尔类型的NestedEnvelope
内的每个值都强制转换为字符串,说“ true”或“ false”,而不是具有实际的bool
类型。 / p>
我转向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{}
的内部映射,所以我仍然需要再次遍历内部映射,将它们转换为适当的类型并执行我的值转换。 / p>
所以我的问题是:在这种情况下,Go中采用哪种方式进行处理,最好是单次通过?
上面的JSON示例的预期结果将是:
Envelope {
some: string
nested: InnerEnvelope {
some: string {
nested: InnerEnvelope {
some: string
}
}
}
答案 0 :(得分:0)
给出您的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 {}方法更优雅。