如何取消封送一个JSON字段,该字段要么是结构体,要么是结构体数组?

用例

我有一个API,在其中我将用户输入作为对象或对象数组接收。喜欢这个:


不带数组的 JSON

{

  "sign": {

    "page_no": 1,

    "x_coord": 100,

    "y_coord": 300

  }

}

带有数组的 JSON

{

  "sign": [

    {

      "page_no": 1,

      "x_coord": 100,

      "y_coord": 300

    },

    {

      "page_no": 2,

      "x_coord": 200,

      "y_coord": 400

    }

  ]

}

结构到昂马沙尔到

type Document struct {

  Sign []Sign `json:"sign"` // or just Sign

}


type Sign struct {

  PageNo int `json:"page_no"`

  XCoord int `json:"x_coord"`

  YCoord int `json:"y_coord"`

}

由于遗留的原因,我无法将上的字段作为所有用户输入的数组,因此它需要既是数组又只是。SignDocumentSignSign


如何取消封送,以便它可以处理下面的两个JSON请求?


我知道那件事。。。

我们可以使用而不是结构,但这会导致太多的关键断言,当我使用结构时,您不必这样做,因为我可以为它们利用零值。map[string]interface{}


另外,这个答案在堆栈溢出似乎没问题,但我想知道有没有更好的方法来做到这一点?


慕沐林林
浏览 124回答 3
3回答

偶然的你

使用自定义 json 取消封口方法创建切片类型。然后,在该解编中,您可以检测您拥有的输入类型,并相应地执行操作。此方法在我的视频 Go 中的高级 JSON 处理中进一步详细说明。type Signs []Signfunc (s *Signs) UnmarshalJSON(d []byte) error {    if d[0] == '{' {        // We know it's a single object        var v Sign        err := json.Unmarshal(d, &v)        *s = Signs{v}        return err    }    // Otherwise it's an array    var v []Sign    err := json.Unmarshal(d, &v)    *s = Signs(v)    return err}

慕虎7371278

可以通过实现自定义取消封口程序,在完全没有(或类型断言)的情况下执行此操作。我会通过窥视JSON内部并检查它是否以方括号或大括号开头来实现取消元帅...跳过空格。interface{}请参阅 json。文档中的解封接口。type Document struct {    Sign SignList}type SignList []Signfunc (l *SignList) UnmarshalJSON(d []byte) error {    for _, b := range d {        switch b {        // These are the only valid whitespace in a JSON object.        case ' ', '\n', '\r', '\t':        case '[':            return json.Unmarshal(d, (*[]Sign)(l))        case '{':            var obj Sign            if err := json.Unmarshal(d, &obj); err != nil {                return err            }            *l = []Sign{obj}            return nil        default:            return errors.New("sign must be object or list")        }    }    return errors.New("sign must be object or list")}这似乎有点笨拙。哦,好吧。除了编码/json 之外,还有用于 Go 的替代 JSON 取消编组库。如果您愿意,请尝试使用替代的 JSON 库。此代码仅适用于编码/json。下面介绍如何测试此代码是否正常工作:package mainimport (    "fmt"    "encoding/json"    "errors")type Sign struct {    X int}func main() {    cases := []string {        `{"Sign": {"X": 1}}`,        `{"Sign": [{"X": 1}, {"X": 2}]}`,    }    for _, c := range cases {        var doc Document        if err := json.Unmarshal([]byte(c), &doc); err != nil {            fmt.Println("Error:", err)            continue        }        fmt.Printf("Document: %+v\n", &doc)    }}打印如下:Document: &{Sign:[{X:1}]}Document: &{Sign:[{X:1} {X:2}]}

繁星淼淼

实现一个可以验证数据的类型进行测试,并将其用作检查。例如:package maintype SignTest struct {    Sign map[string]interface{} `json:"sign"`}func main() {    s := `{  "sign": [    {      "page_no": 1,      "x_coord": 100,      "y_coord": 300    },    {      "page_no": 2,      "x_coord": 200,      "y_coord": 400    }  ]}`    err := json.Unmarshal([]byte(s), &SignTest{})    if err != nil {        fmt.Println("Document Type")    } else {        fmt.Println("Sign Type")    }}打印 ,而Document Typepackage maintype SignTest struct {    Sign map[string]interface{} `json:"sign"`}func main() {    s := `{  "sign": {    "page_no": 1,    "x_coord": 100,    "y_coord": 300  }}`    err := json.Unmarshal([]byte(s), &SignTest{})    if err != nil {        fmt.Println("Document Type")    } else {        fmt.Println("Sign Type")    }}指纹。Sign Type但是,在取消编组符号以外的对象是否是数组时,这里可能会出错,如果您想要更安全,请检查错误的错误消息,该错误应按预期方式假设为 。Document
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go