是否可以部分解码和更新JSON? (走)

时间:2015-03-17 23:47:27

标签: json go

我只需要解码和更新json对象的特定值。 问题是我不知道对象的完整结构。 encoding / json包"忽略" /截断结构中未提供的字段,因此编码这些字段时会丢失。   我想知道是否可以解组我所知道的结构,更新它然后封送它而不截断/删除未知的结构/信息。

2 个答案:

答案 0 :(得分:1)

似乎有可能。

package main

import (
    "encoding/json"
    "fmt"
    "log"
)

func main() {
    type Color struct {
        Space string
        Point json.RawMessage // delay parsing until we know the color space
    }
    type RGB struct {
        R uint8
        G uint8
        B uint8
    }
    type YCbCr struct {
        Y  uint8
        Cb int8
        Cr int8
    }

    var j = []byte(`
        {"Space": "YCbCr", "Point": {"Y": 255, "Cb": 0, "Cr": -10}}`)
    var colors Color
    err := json.Unmarshal(j, &colors)
    if err != nil {
        log.Fatalln("error:", err)
    }
    colors.Space = "no-space"

    b, err := json.Marshal(&colors)
    if err != nil {
        panic(err)
    }
    fmt.Printf("b is now %s", b)
    return

}

答案 1 :(得分:0)

我知道这是一个非常老的问题,但是我了解到通常的struct和json.RawMessage的组合将在这种情况下起作用。让我分享。

重点是:将整个数据保存在raw字段中,然后将其用于编码/解码。可以从那里派生其他字段。

package main

import (
    "encoding/json"
    "log"
)

type Color struct {
    Space string
    raw   map[string]json.RawMessage
}

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
}

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)
}

func main() {
    before := []byte(`{"Space": "YCbCr", "Point": {"Y": 255, "Cb": 0, "Cr": -10}}`)
    log.Println("before: ", string(before))

    // decode
    color := new(Color)
    err := json.Unmarshal(before, color)
    if err != nil {
        log.Fatal(err)
    }

    // modify fields of interest
    color.Space = "RGB"

    // encode
    after, err := json.Marshal(color)
    if err != nil {
        log.Fatal(err)
    }
    log.Println("after:  ", string(after))
}

输出应如下所示:

2020/09/03 01:11:33 before:  {"Space": "YCbCr", "Point": {"Y": 255, "Cb": 0, "Cr": -10}}
2020/09/03 01:11:33 after:   {"Point":{"Y":255,"Cb":0,"Cr":-10},"Space":"RGB"}

注意:这不会保留键顺序或缩进。