dtz30833 2014-09-25 08:39
浏览 49
已采纳

在Go中解组顶级JSON数组

I'm learning Go by writing a simple http server and I need to handle some JSON responses.

With an object response, I can unmarshal it idiomatically with 2 lines of code: structResult := Foo{} json.Unmarshal(structBody, &structResult)

I don't know how to do the same for an array response (see the example below). Is there a way to specify (possibly via json tag) that top-level array should go into a given struct field?

package main

import "fmt"
import "encoding/json"

type Foo struct {
    Id uint64 `json:"id"`
    Name string `json:"name"`
}

type BaseResult struct {
    Error string  `json:"error"`
}

type FooResult struct {
    BaseResult
    Foos []Foo
}

func main() {
    // Simple and works.
    structBody := []byte(`{"id": 1,"name": "foo"}`)
    structResult := Foo{}
    json.Unmarshal(structBody, &structResult)
    fmt.Printf("%#v
", structResult)

    // Doesn't work.
    arrayBody := []byte(`[{"id": 1,"name": "foo"},{"id": 2,"name": "bar"},{"id": 3,"name": "foobar"}]`) 
    arrayResult := FooResult{}
    json.Unmarshal(arrayBody, &arrayResult)
    fmt.Printf("%#v
", arrayResult)
}

I know I could make FooResult an array:

type FooResult []Foo

but then I lose the ability to specify base object which I would like to use to store error message and such. I also know that I can unmarshal into &fooResult.Foos directly, but I want the code to work with both objects and arrays.

UPDATE

Implementing UnmarshalJSON as suggested by @dyoo partially solves my problem, but I was hoping that I could use BaseResult to store parse error in case JSON has a different structure:

arrayBody := []byte(`{"error": "foo"}`)
arrayResult := FooResult{}
json.Unmarshal(arrayBody, &arrayResult)
fmt.Printf("%#v
", arrayResult)

Of course I could implement more complex logic inside UnmarshalJSON - but isn't there a simpler way to do it?

  • 写回答

2条回答

  • douhao3562 2014-09-25 18:05
    关注

    You can implement the json.Unmarshaler interface in your FooResult, to customize exactly how it responds to unmarshaling. (Similarly, there's a json.Marshaler interface.)

    Add:

    func (f *FooResult) UnmarshalJSON(bs []byte) error {
        return json.Unmarshal(bs, &f.Foos)
    }
    

    after which your code should otherwise work. http://play.golang.org/p/oMdoB2e-rB

    You might try something like:

    func (f *FooResult) UnmarshalJSON(bs []byte) error {
        err1 := json.Unmarshal(bs, &f.BaseResult)
        err2 := json.Unmarshal(bs, &f.Foos)
        if err1 != nil && err2 != nil {
            // Arbitrarily choose an error.
            return err1
        }
        return nil
    }
    

    although even this is beginning to look dubious. Handling union type results is not quite what the json library is designed to handle automatically for you. You'll need to explicitly code the coercion logic if your JSON has dynamic type.

    See: How to unmarshall an array of different types correctly? and http://blog.golang.org/json-and-go for related issues.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题
  • ¥50 Kubernetes&Fission&Eleasticsearch
  • ¥15 報錯:Person is not mapped,如何解決?
  • ¥15 c++头文件不能识别CDialog
  • ¥15 Excel发现不可读取的内容