在处理 JSON 数据时,通常需要在没有对象完整结构的情况下访问和修改特定值。 Go 中的encoding/json 包虽然提供了强大的解码和编码功能,但会截断或忽略目标结构中未明确定义的字段。这可能会导致重新编码时丢失未知信息。
为了克服这一挑战,可以利用常规结构体和 json 的组合。 RawMessage实现部分解码和更新。 json.RawMessage 表示原始 JSON 数据,允许保存任何 JSON 结构而无需解码其特定形式。
在下面的代码片段中,Color 结构体是使用 Space 字段和类型为 map[ 的原始字段定义的字符串]json.RawMessage。这样可以存储整个 JSON 对象,同时仅显式解组已知字段 (Space)。
type Color struct { Space string raw map[string]json.RawMessage }
在解组过程中,UnmarshalJSON 方法提取 Space 字段来自原始数据(如果存在)。完整的原始数据存储在原始地图中。
func (c *Color) UnmarshalJSON(bytes []byte) error { if err := json.Unmarshal(bytes, &c.raw); err != nil { return err } if space, ok := c.raw["Space"]; ok { if err := json.Unmarshal(space, &c.Space); err != nil { return err } } return nil }
更新值时,仅需要修改已知字段。在这种情况下,可以为 color.Space 分配一个新值。
编组期间,MarshalJSON 方法检索更新的空间值并将其存储为 json.RawMessage 之前的原始映射中将整个对象编码为 JSON。
func (c *Color) MarshalJSON() ([]byte, error) { bytes, err := json.Marshal(c.Space) if err != nil { return nil, err } c.raw["Space"] = json.RawMessage(bytes) return json.Marshal(c.raw) }
以下示例演示 JSON 对象的部分解码和更新:
before := []byte(`{"Space": "YCbCr", "Point": {"Y": 255, "Cb": 0, "Cr": -10}}`) // Decode color := new(Color) err := json.Unmarshal(before, color) // Modify the Space field color.Space = "RGB" // Encode after, err := json.Marshal(color)
输出将是:
{"Point":{"Y":255,"Cb":0,"Cr":-10},"Space":"RGB"}
这种方法保留了未知的结构和信息,允许部分解码和更新JSON 对象。
以上是如何在Go中部分解码和更新JSON数据而不丢失未知信息?的详细内容。更多信息请关注PHP中文网其他相关文章!