【问题标题】:Unmarshal json array to struct将 json 数组解组为结构
【发布时间】:2014-04-27 01:16:30
【问题描述】:

我有一组自定义值

[
    1,
    "test",
    { "a" : "b" }
]

我可以解组到 []interface{},但这不是我想要的。

我想将此数组解组为结构

type MyType struct {
    Count int
    Name string
    Relation map[string]string
}

在 Go 中是否可以使用标准库或侧库?

【问题讨论】:

  • golang.org/pkg/encoding/json 解释细节并包含示例。
  • @Volker 我以前读过它,但找不到我的问题的解决方案。你能指出我在哪里解释了如何解决这个问题吗?具体是什么例子?

标签: json go


【解决方案1】:

其他答案似乎太复杂了,这里是另一种方法:

package main

import (
   "encoding/json"
   "fmt"
)

type myType struct {
   count int
   name string
   relation map[string]string
}

func (t *myType) UnmarshalJSON(b []byte) error {
   a := []interface{}{&t.count, &t.name, &t.relation}
   return json.Unmarshal(b, &a)
}

func main() {
   var t myType
   json.Unmarshal([]byte(`[1, "test", {"a": "b"}]`), &t)
   fmt.Printf("%+v\n", t)
}

https://eagain.net/articles/go-json-array-to-struct

【讨论】:

    【解决方案2】:

    您可以使用github.com/ugorji/go/codec,它可以将数组解组为结构:

    将结构编码为数组,并从数据流中的数组解码结构

    尽管该库宣传“编码/json 的直接替换” - 它仅与 json: 标记有关。所以你必须使用codec.Decoder 而不是json.Unmarshal:

    package main
    
    import "fmt"
    import "github.com/ugorji/go/codec"
    
    type MyType struct {
        Count    int
        Name     string
        Relation map[string]string
    }
    
    func main() {
        x := &MyType{}
        data := []byte(`[1,"test",{"a":"b"}]`)
        codec.NewDecoderBytes(data, new(codec.JsonHandle)).Decode(x)
        fmt.Println(x)
    }
    

    【讨论】:

    • 您能在回答中举个例子吗?
    【解决方案3】:

    这是一个元组,可以将元组解组到一个结构中,但 encoding/json 不支持。

    但是我们可以使用以下辅助函数,它遍历结构的字段并解组它们:

    // UnmarshalJSONTuple unmarshals JSON list (tuple) into a struct.
    func UnmarshalJSONTuple(text []byte, obj interface{}) (err error) {
        var list []json.RawMessage
        err = json.Unmarshal(text, &list)
        if err != nil {
            return
        }
    
        objValue := reflect.ValueOf(obj).Elem()
        if len(list) > objValue.Type().NumField() {
            return fmt.Errorf("tuple has too many fields (%v) for %v",
                len(list), objValue.Type().Name())
        }
    
        for i, elemText := range list {
            err = json.Unmarshal(elemText, objValue.Field(i).Addr().Interface())
            if err != nil {
                return
            }
        }
        return
    }
    

    所以你只需要提供UnmarshalJSON方法:

    func (this *MyType) UnmarshalJSON(text []byte) (err error) {
        return UnmarshalJSONTuple(text, this)
    }
    

    这里是完整的例子:http://play.golang.org/p/QVA-1ynn15

    【讨论】:

      【解决方案4】:

      由于您的 json 在数组中保存了不同类型的值,因此无法简单地使用 go 解析它。如果您可以控制 json 输入的格式,请将三个值包装在 {} 中以形成一个对象,如下所示:

      [
          {
              "Count": 1,
              "Name": "test",
              "Relation": { "a" : "b" }
           }
      ]
      

      然后解析成你的结构应该可以工作。

      如果您无法控制 json 输入。将其解析为 []interface{},然后手动将值分配给您的结构。尽管这可能会变得很棘手,但这取决于您想要支持的可能响应的复杂性。

      请注意,此问题指向 golangs json 解析方法的核心限制,因此 - 据我所知 - 库也无法解决它。

      【讨论】:

      • 不,据我所见,它不起作用,并且您提供的 json 无效:( 手动分配值很复杂,我正在寻找可以实现它的库
      • 你说得对,我在 json 对象中丢失了键,对此感到抱歉。一般来说,如果你有这样的问题,我建议使用你的目标值的虚拟实例和Encode 它,看看它会产生什么样的输出(因此希望找到Decode 的输入)
      • 看github.com/likexian/simplejson,不过我觉得也解决不了你的问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-25
      • 1970-01-01
      • 2018-07-16
      • 1970-01-01
      • 2021-08-09
      • 2018-05-16
      相关资源
      最近更新 更多