如何解组 JSON?

Posted

技术标签:

【中文标题】如何解组 JSON?【英文标题】:How do I Unmarshal JSON? 【发布时间】:2014-05-22 05:13:48 【问题描述】:

我正在尝试将 JSON 解组为一个结构。但是,该结构有一个带有标签的字段。使用反射,我尝试查看标签中是否包含字符串“json”。如果是这样,那么要解组的 json 应该简单地作为字符串解组到字段中。

例子:

const data = `"I":3, "S":"phone": "sales": "2223334444"`
type A struct 
    I int64
    S string `sql:"type:json"`

问题很简单 - 将 json 中的“S”作为字符串解组到结构 A 中。

这就是我已经走了多远。但是我被困在这里了。

http://play.golang.org/p/YzrhjuXxGN

【问题讨论】:

【参考方案1】:

这是最好的方法 - 不需要反射。创建一个新类型RawString 并为其创建MarshalJSONUnmarshalJSON 方法。 (playground)

// RawString is a raw encoded JSON object.
// It implements Marshaler and Unmarshaler and can
// be used to delay JSON decoding or precompute a JSON encoding.
type RawString string

// MarshalJSON returns *m as the JSON encoding of m.
func (m *RawString) MarshalJSON() ([]byte, error) 
    return []byte(*m), nil


// UnmarshalJSON sets *m to a copy of data.
func (m *RawString) UnmarshalJSON(data []byte) error 
    if m == nil 
        return errors.New("RawString: UnmarshalJSON on nil pointer")
    
    *m += RawString(data)
    return nil


const data = `"i":3, "S":"phone": "sales": "2223334444"`

type A struct 
    I int64
    S RawString `sql:"type:json"`


func main() 
    a := A
    err := json.Unmarshal([]byte(data), &a)
    if err != nil 
        log.Fatal("Unmarshal failed", err)
    
    fmt.Println("Done", a)

我修改了RawMessage的实现来创建上面的。

【讨论】:

【参考方案2】:

这里的问题是您对两种协议使用一种编码格式,并且您的模型可能有问题。

这是一个有效的 Json 有效负载,应该这样处理。您可以使用的一个技巧是创建 另一个处理“字符串”json 的字段和一个处理“json 结构”的字段。 请参阅此修改示例:我首先解组 json,然后将其编组回 json 以创建最终字符串以上传到数据库。一个字段用于解组,另一个用于与 DB 通信。

package main

import(
"fmt"
"encoding/json"
)


const data = `"i":3, "S":"phone": "sales": "2223334444"`
type A struct 
    I int64
    Sjson struct 
       Phone struct 
          Sales string `json:"sales"`
        `json:"phone"`
     `json:"S", sql:"-"`
    S string `sql:"type:json",json:"-"`


func main() 
    msg := A
    _ = json.Unmarshal([]byte(data), &msg)
    data, _ := json.Marshal(msg.Sjson)
    msg.S = string(data)
    fmt.Println("Done", msg)

【讨论】:

【参考方案3】:

看起来问题是您的代码中的s interface 不可寻址。对于Value.SetString,值必须是可寻址的,并且带有Kind 字符串。你可以查看它的文档 - http://golang.org/pkg/reflect/#Value.SetString

我如何理解SetString 不会更改a 中的值,因为您只使用接口s。在Laws of Reflection 中,您可以找到“reflect.ValueOf 是 x 的副本,而不是 x 本身”(第三定律)。

为了使您的代码正常工作,我做了一些类型断言,并在指向断言结构的指针上使用了reflect.ValueOf

要检查 Value 是否可设置或可寻址,您可以使用 Value.CanSet 广告 Value.CanAddr

工作代码:http://play.golang.org/p/DTriENkzA8

不知道这样做是否正确

【讨论】:

谢谢。但是如果没有类型断言,我们如何做到这一点。我们通常不知道 UnmarshalJsonIntoStruct 函数中的类型(s = l.(A)) @BVSat 你可以为所有可能的结构做一个开关/案例

以上是关于如何解组 JSON?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Akka HTTP 中将“text/plain”解组为 JSON

如何解组具有不同类型值的json数组

如何在单个路由中解组 POST 参数和 JSON 正文?

如何使用 Akka HTTP 解组 json 响应删除不必要的字段

Akka HTTP:如何将 Json 格式响应解组为域对象

Golang如何解组嵌套的JSON数据的子集