在Go语言中解析JSON中的JSON。

huangapple go评论81阅读模式
英文:

Unmarshal JSON in JSON in Go

问题

我想要将一个包含 JSON 字符串的字段解析为一个完整的对象。在 Go 语言中,我该如何做呢?

示例:

输入:

{
  "foo": 1,
  "bar": "{\"a\":\"Hello\"}"
}

Go 类型:

type Child struct {
	A string `json:"a"`
}

type Main struct {
	Foo int   `json:"foo"`
	Bar Child `json:"bar"`
}

我猜我需要在其中一个类型上实现一个自定义的 UnmarshalJSON 方法,但是我不确定是在哪个类型上以及如何实现。

英文:

I want to unmarshal a JSON object where one field contains a JSON string into one coherent object. How do I do that in Go?

Example:

Input:

{
  "foo":1,
  "bar":"{\\"a\\":\\"Hello\\"}"
}

Go type:

type Child struct {
	A string `json:"a"`
}

type Main struct {
	Foo int   `json:"foo"`
	Bar Child `json:"bar"`
}

I guess I'd need to implement a custom UnmarshalJSON implementation on one of the types, but its twisting my head to figure out on which one and how.

答案1

得分: 4

我猜你想把这个JSON字符串当作周围JSON对象的一部分来处理?如果是这样的话,就像你建议的那样,在Child上使用自定义的UnmarshalJSON方法应该可以实现这个。

func (c *Child) UnmarshalJSON(p []byte) error {
    var jsonString string
    if err := json.Unmarshal(p, &jsonString); err != nil {
        return err // 表示字符串无效
    }
    type C Child // 一个没有UnmarshalJSON方法的新类型
    return json.Unmarshal([]byte(jsonString), (*C)(c))
}

在 playground 上查看

英文:

I guess you want to treat this as if the JSON String were just part of the surrounding JSON object? If so, then yes, as you suggest, a custom UnmarshalJSON method on Child should accomplish this.

func (c *Child) UnmarshalJSON(p []byte) error {
    var jsonString string
    if err := json.Unmarshal(p, &jsonString); err != nil {
        return err // Means the string was invalid
    }
    type C Child // A new type that doesn't have UnmarshalJSON method
	return json.Unmarshal([]byte(jsonString), (*C)(c))
}

See it in the playground

答案2

得分: 0

如果我要为该数据创建一个自定义的UnmarshalJson,我会创建一个辅助结构体auxMain,它与主结构体具有相同的字段,但Bar字段为字符串。然后,它将JSON数据解组到这个辅助结构体中,提取Foo字段和Bar字段作为字符串。之后,它将Bar字段作为字符串解组到Child结构体中,并将提取的Foo字段和Child结构体赋给主结构体。

这是一种绕弯的方式,但在Playground中似乎可以工作。

func (m *Main) UnmarshalJSON(b []byte) error {
	type auxMain struct {
		Foo int    `json:"foo"`
		Bar string `json:"bar"`
	}
	var a auxMain
	if err := json.Unmarshal(b, &a); err != nil {
		return err
	}
	var child Child
	if err := json.Unmarshal([]byte(a.Bar), &child); err != nil {
		return err
	}
	m.Foo = a.Foo
	m.Bar = child
	return nil
}

在Playground中尝试一下,看看效果:https://go.dev/play/p/wWIceUxu1tj

不知道这是否符合你的要求。

英文:

if i were to create a custom UnmarshalJson for that data, I would create an auxiliary struct auxMain that has the same fields as the main struct but with Bar field as string. Then it unmarshals the JSON data into this auxiliary struct, extracting the Foo field and the Bar field as a string. After that, it unmarshals the Bar field as string into the Child struct, and assigns the extracted Foo field and the Child struct to the Main struct.

It's a round about way but seems to work in the playground.

func (m *Main) UnmarshalJSON(b []byte) error {
	type auxMain struct {
		Foo int    `json:"foo"`
		Bar string `json:"bar"`
	}
	var a auxMain
	if err := json.Unmarshal(b, &a); err != nil {
		return err
	}
	var child Child
	if err := json.Unmarshal([]byte(a.Bar), &child); err != nil {
		return err
	}
	m.Foo = a.Foo
	m.Bar = child
	return nil
}

try it out in the PlayGround and see: https://go.dev/play/p/wWIceUxu1tj

Don't know if this is what you are looking for.

huangapple
  • 本文由 发表于 2023年1月13日 00:04:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/75099156.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定