繁体   English   中英

编组时忽略 JSON 标签

[英]Ignore JSON tags when marshalling

我正在从外部来源获取 JSON 数据。 这个 JSON 中的字段名称不是我想随身携带的东西,所以我使用json:"originalname"标签将它们转换为对我有意义的名称。

当我将这样的对象编组回 JSON 时,我自然会再次获得丑陋的(原始)名称。

有没有办法在编组时忽略标签? 或者为 marshall 和 unmarshall 指定不同名称的方法?

为了澄清起见,我在操场上准备了一个示例,并在下面粘贴了相同的代码。

提前致谢。

package main

import (
    "encoding/json"
    "fmt"
)

type Band struct {
    Name   string `json:"bandname"`
    Albums int    `json:"albumcount"`
}

func main() {
    // JSON -> Object
    data := []byte(`{"bandname": "AC/DC","albumcount": 10}`)
    band := &Band{}
    json.Unmarshal(data, band)

    // Object -> JSON
    str, _ := json.Marshal(band)
    fmt.Println("Actual Result: ", string(str))
    fmt.Println("Desired Result:", `{"Name": "AC/DC","Albums": 10}`)

    // Output:
    // Actual Result:  {"bandname":"AC/DC","albumcount":10}
    // Desired Result: {"Name": "AC/DC","Albums": 10}
}

你可以实施

type Marshaler interface {
        MarshalJSON() ([]byte, error)
}

来自标准库的encoding/json包。 例子:

type Band struct {
    Name   string `json:"bandname"`
    Albums int    `json:"albumcount"`
}

func (b Band) MarshalJSON() ([]byte, error) {
    n, _ := json.Marshal(b.Name)
    a, _ := json.Marshal(b.Albums)
    return []byte(`{"Name":` + string(n) + `,"Albums":` + string(a) + `}`)
}

诚然,这不是一个很好的解决方案。

作为通用解决方案,您可以使用反射来创建一个新类型,该类型删除 json 标记,然后对其进行编组。

func getVariantStructValue(v reflect.Value, t reflect.Type) reflect.Value {
    sf := make([]reflect.StructField, 0)
    for i := 0; i < t.NumField(); i++ {
        sf = append(sf, t.Field(i))

        if t.Field(i).Tag.Get("json") != "" {
            sf[i].Tag = ``
        }
    }
    newType := reflect.StructOf(sf)
    return v.Convert(newType)
}

func MarshalIgnoreTags(obj interface{}) ([]byte, error) {
    value := reflect.ValueOf(obj)
    t := value.Type()
    newValue := getVariantStructValue(value, t)
    return json.Marshal(newValue.Interface())
}

您只需使用以下方法调用它:

str, _ := MarshalIgnoreTags(band)

做相反的事情有点棘手(在解组 JSON 时忽略标签),但可以使用mapstructure

func UnmarshalIgnoreTags(data []byte, obj interface{}) error {
    rv := reflect.ValueOf(obj)
    if rv.Kind() != reflect.Ptr || rv.IsNil() {
        return errors.New("unmarshal destination obj must be a non-nil pointer")
    }

    value := reflect.Indirect(rv)
    t := value.Type()

    newValue := getVariantStructValue(value, t)
    i := newValue.Interface()
    err := json.Unmarshal(data, &i)
    if err == nil {
        // We use mapstructure because i is of type map[string]interface{} and it's the easiest way to convert back to struct type
        // See: https://stackoverflow.com/a/38939459/2516916
        mapstructure.Decode(i, obj)
    }

    return err
}

在此处查看游乐场: https : //play.golang.org/p/XVYGigM71Cf

您还可以使用本线程中提到的库: https : //stackoverflow.com/a/50966527/5649638

这会给你一个这样的结构:

type TestJson struct {
    Name string `json:"name" newtag:"newname"`
    Age  int    `json:"age" newtag:"newage"`
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM