如何将两个 JSON 值解组到同一个变量中?

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

How to unmarshal two json values into same variable?

问题

我经常遇到具有相同结构但不同名称的 JSON 数据。如何将它们都分配给同一个结构体?例如:

{
    "e":"g",
    "a":[
        {
            "b":"b1",
            "c":"c1"
        }
    ]
}

{
    "e":"f",
    "d":[
        {
            "b":"b1",
            "c":"c1"
        }
    ]
}

这两个 JSON 数据具有相同的内部结构,但无法解析为相同的 Golang 结构体。

英文:

I frequently come across json that have same structure but different name. How is it possible to assign all of them in same struct. for example

{
    "e":"g"
    "a":[
        {
            "b":"b1",
            "c":"c1"
        }
        ]
}

and

{
    "e":"f"
    "d":[
        {
            "b":"b1",
            "c":"c1"
        }
        ]
}

have same internal structure but could not be unmarsheled into same golang struct.

答案1

得分: 1

使用结构标签来解码JSON是为了最常见的用例。对于自定义行为,请实现Unmarshaler接口(https://play.golang.org/p/rCpCDvWXGP):

type InnerStruct struct {
    B, C string
}
type OuterStruct struct {
    E string
    A []InnerStruct
}

func (o *OuterStruct) UnmarshalJSON(bs []byte) error {
    var intermediate map[string]json.RawMessage
    err := json.Unmarshal(bs, &intermediate)
    if err != nil {
        return err
    }
    // e is just e
    e, ok := intermediate["e"]
    if !ok {
        return fmt.Errorf("invalid json, expected `e`")
    }
    err = json.Unmarshal(e, &o.E)
    if err != nil {
        return err
    }
    // a is a or d
    a, ok := intermediate["a"]
    if !ok {
        a, ok = intermediate["d"]
    }
    if !ok {
        return fmt.Errorf("invalid json, expected `a` or `d`")
    }
    err = json.Unmarshal(a, &o.A)
    if err != nil {
        return err
    }
    return nil
}

在这个例子中,我使用了一个中间映射,并延迟处理内部值以匹配ad。我确定这不是你要处理的实际数据,但希望这足以让你开始。

英文:

Using struct tags for decoding json is intended for the most common use cases. For custom behavior implement the Unmarshaler interface (https://play.golang.org/p/rCpCDvWXGP):

type InnerStruct struct {
	B, C string
}
type OuterStruct struct {
	E string
	A []InnerStruct
}

func (o *OuterStruct) UnmarshalJSON(bs []byte) error {
	var intermediate map[string]json.RawMessage
	err := json.Unmarshal(bs, &intermediate)
	if err != nil {
		return err
	}
    // e is just e
	e, ok := intermediate["e"]
	if !ok {
		return fmt.Errorf("invalid json, expected `e`")
	}
	err = json.Unmarshal(e, &o.E)
	if err != nil {
		return err
	}
    // a is a or d
	a, ok := intermediate["a"]
	if !ok {
		a, ok = intermediate["d"]
	}
	if !ok {
		return fmt.Errorf("invalid json, expected `a` or `d`")
	}
	err = json.Unmarshal(a, &o.A)
	if err != nil {
		return err
	}
	return nil
}

In this case I used an intermediate map and delayed the processing of the inner values to match a or d. I'm sure this wasn't the actual data you had to work with, but hopefully it's enough to get you started.

huangapple
  • 本文由 发表于 2015年8月1日 19:54:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/31761539.html
匿名

发表评论

匿名网友

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

确定