自定义 JSON 编组(Marshaling)

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

Custom Json Marshaling

问题

我在Go语言中使用第三方的JSON API。它有一些返回键值对数据的端点。例如,这是一个关于状态的JSON示例:

{
"result": {
"0": "done",
"1": "incomplete",
"2": "completed",
....
}
}

你可以看到,它不是一个数组,而是一个对象。你想知道是否可以将这种类型的JSON解组为对象数组,类似于:

type Status struct {
Id int
Status string
}

而不使用额外的结构体,例如:

type StatusResponse struct {
Result map[string]string json:"result"
}

以及提取值的代码吗?

英文:

I have a third-party json api to work with in go.
It has some endpoints which return data as key-value.
For example here is json for statuses:

{
  "result": {
    "0": "done",
    "1": "incomplete",
    "2": "completed",
    ....
  }
}

So as you see it is not an array it is an object.
Is it possible to marshal this kind of json to array of objects like

type Status struct {
    Id int
    Status string
}

without using additional struct like

type StatusReposne struct {
    Result map[string]string `json:"result"`
}

and code to extract values?

答案1

得分: 2

根据@mkopriva在评论中的说法,如果不进行一些额外的工作是不可能的。这段代码提供了将数据编组/解组到一个Status切片的方法:

func main() {
    sr := new(StatusReposne)

    json.Unmarshal([]byte(input), sr)
    fmt.Printf("%+v\n", sr)

    js, _ := json.Marshal(sr)
    fmt.Printf("%s\n", js)
}

type StatusReposne struct {
    Result []Status `json:"result"`
}

type Status struct {
    Id     int
    Status string
}

func (x *StatusReposne) MarshalJSON() ([]byte, error) {
    var buffer struct {
        Result map[string]string `json:"result"`
    }
    buffer.Result = make(map[string]string)
    for _, v := range x.Result {
        buffer.Result[strconv.Itoa(v.Id)] = v.Status
    }
    return json.Marshal(&buffer)
}

func (x *StatusReposne) UnmarshalJSON(b []byte) error {
    var buffer struct {
        Result map[string]string `json:"result"`
    }
    buffer.Result = make(map[string]string)
    json.Unmarshal(b, &buffer)
    for k, v := range buffer.Result {
        k, _ := strconv.Atoi(k)
        x.Result = append(x.Result, Status{Id: k, Status: v})
    }
    return nil
}

var input = `{
  "result": {
    "0": "done",
    "1": "incomplete",
    "2": "completed"
  }
}`

以上是要翻译的内容。

英文:

As @mkopriva stated in the comment, it's not possible without some extra work. This code does provide means to Marshal/Unmarshal data to/from a slice of Statuss:

func main() {
sr := new(StatusReposne)
json.Unmarshal([]byte(input), sr)
fmt.Printf("%+v\n", sr)
js, _ := json.Marshal(sr)
fmt.Printf("%s\n", js)
}
type StatusReposne struct {
Result []Status `json:"result"`
}
type Status struct {
Id     int
Status string
}
func (x *StatusReposne) MarshalJSON() ([]byte, error) {
var buffer struct {
Result map[string]string `json:"result"`
}
buffer.Result = make(map[string]string)
for _, v := range x.Result {
buffer.Result[strconv.Itoa(v.Id)] = v.Status
}
return json.Marshal(&buffer)
}
func (x *StatusReposne) UnmarshalJSON(b []byte) error {
var buffer struct {
Result map[string]string `json:"result"`
}
buffer.Result = make(map[string]string)
json.Unmarshal(b, &buffer)
for k, v := range buffer.Result {
k, _ := strconv.Atoi(k)
x.Result = append(x.Result, Status{Id: k, Status: v})
}
return nil
}
var input = `{
"result": {
"0": "done",
"1": "incomplete",
"2": "completed"
}
}`

huangapple
  • 本文由 发表于 2017年4月2日 02:33:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/43160569.html
匿名

发表评论

匿名网友

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

确定