使用json.RawMessage解析嵌套的JSON字符串。

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

Unmarshaling nested json string use json.RawMessage

问题

我很难理解如何解组先前解组的 JSON 字节数组生成的原始 JSON 字符串。以下是你的代码:

type Message struct {
    Event string
    Data json.RawMessage  // 数据的解析方式取决于事件类型
}

type CreateMessage struct {
    id int
}

var evt = []byte(`{"event": "create", "data" :{"id":5 }}`)

func main() {
    var message Message
    log.Println(string(evt))
    json.Unmarshal(evt, &message)

    log.Println(message)
    log.Println(message.Event)
    log.Println(string(message.Data))
    fmt.Printf("%+v\n", message)

    var message2 = new(CreateMessage)
    err := json.Unmarshal(message.Data, &message2)

    log.Println(message2)
    log.Println(err)
}

输出结果为:

2015/06/29 23:22:10 {"event": "create", "data" :{"id":5 }}
2015/06/29 23:22:10 {create [123 34 105 100 34 58 53 32 125]}
2015/06/29 23:22:10 create
2015/06/29 23:22:10 {"id":5 }
{Event:create Data:[123 34 105 100 34 58 53 32 125]}
2015/06/29 23:22:10 &{0}
2015/06/29 23:22:10 <nil>

为什么我不能将数据解组为 `CreateMessage` 对象我尝试了这里的示例http://golang.org/pkg/encoding/json/#RawMessage.UnmarshalJSON)和这里的示例(https://stackoverflow.com/questions/20101954/go-json-unmarshal-nested-object-into-string-or-byte),但它们都没有解组嵌套的原始 JSON 数据,而这正是我想要做的。

<details>
<summary>英文:</summary>

I&#39;m having trouble wrapping my head around how to unmarshal a raw json string that was from a previously unmarshaled json byte array. I have the current code:

    type Message struct {
        Event string
        Data json.RawMessage  // how data is parsed depends on the event
    }

    type CreateMessage struct {
        id int
    }

    var evt = []byte(`{&quot;event&quot;: &quot;create&quot;, &quot;data&quot; :{&quot;id&quot;:5 }}`)

    func main() {
        var message Message
        log.Println(string(evt))
        json.Unmarshal(evt, &amp;message)

        log.Println(message)
        log.Println(message.Event)
        log.Println(string(message.Data))
        fmt.Printf(&quot;%+v\n&quot;, message)

        var message2 = new(CreateMessage)
        err := json.Unmarshal( message.Data, &amp;message2 )

        log.Println(message2)
        log.Println(err)
    }

And the output is:

    2015/06/29 23:22:10 {&quot;event&quot;: &quot;create&quot;, &quot;data&quot; :{&quot;id&quot;:5 }}
    2015/06/29 23:22:10 {create [123 34 105 100 34 58 53 32 125]}
    2015/06/29 23:22:10 create
    2015/06/29 23:22:10 {&quot;id&quot;:5 }
    {Event:create Data:[123 34 105 100 34 58 53 32 125]}
    2015/06/29 23:22:10 &amp;{0}
    2015/06/29 23:22:10 &lt;nil&gt;

Why can&#39;t I unmarshal data as a `CreateMessage` object? I tried the example [here](http://golang.org/pkg/encoding/json/#RawMessage.UnmarshalJSON) and [here](https://stackoverflow.com/questions/20101954/go-json-unmarshal-nested-object-into-string-or-byte) but they don&#39;t unmarshal the nested raw json data and that is exactly what I&#39;m trying to do.

</details>


# 答案1
**得分**: 4

问题很简单`CreateMessage` 结构体的 `id` 字段是未导出的它以小写字母开头将其改为

```go
type CreateMessage struct {
    Id int
}

然后它就会正常工作。

注意:

由于 message2 已经是一个指针(new(CreateMessage)),你不需要将其地址传递给 json.Unmarshal(),只传递其值就足够了:

var message2 = new(CreateMessage)
if err := json.Unmarshal(message.Data, message2); err != nil {
    panic(err)
}
log.Printf("%+v", message2)

输出:

2009/11/10 23:00:00 &{Id:5}

或者根本不使用 new()

var message2 CreateMessage
if err := json.Unmarshal(message.Data, &message2); err != nil {
    panic(err)
}
log.Printf("%+v", message2)

输出:

2009/11/10 23:00:00 {Id:5}

Go Playground 上尝试一下。

还要注意,现在字段的名称是 Id,而 JSON 中包含 id,但 json 包足够“智能”,可以匹配它们(Eventevent 也是一样)。但要知道,如果你尝试对结构体进行编组,输出将包含 Id 而不是 id

如果你想使用完全不同的字段名,或者确保在对结构体进行编组时它会变成小写,你可以使用结构体标签来指定它在 JSON 文本中的显示方式,例如:

type CreateMessage struct {
    MyId int `json:"id"`
}
英文:

The problem is simply that the id field of the CreateMessage struct is unexported, it starts with a lowercase letter. Change it to:

type CreateMessage struct {
Id int
}

And it will work.

Notes:

Since message2 is already a pointer (new(CreateMessage)), you don't have to pass its address to json.Unmarshal(), its value is enough:

var message2 = new(CreateMessage)
if err := json.Unmarshal(message.Data, message2); err != nil {
panic(err)
}
log.Printf(&quot;%+v&quot;, message2)

Output:

2009/11/10 23:00:00 &amp;{Id:5}

Or don't use new() at all:

var message2 CreateMessage
if err := json.Unmarshal(message.Data, &amp;message2); err != nil {
panic(err)
}
log.Printf(&quot;%+v&quot;, message2)

Output:

2009/11/10 23:00:00 {Id:5}

Try it on the Go Playground.

Also note that now the name of the field is &quot;Id&quot; and JSON contains &quot;id&quot; but the json package is "intelligent" enough to match them (same with &quot;Event&quot; and &quot;event&quot;). But know that if you would ever try to marshal your structs, the output would contain &quot;Id&quot; and not &quot;id&quot;.

If you want to use a completely different field name or make sure it will be lowercased when you marshal your structs, you can use struct tags to tell how it should appear in the JSON text, for example:

type CreateMessage struct {
MyId int `json:&quot;id&quot;`
}

huangapple
  • 本文由 发表于 2015年6月30日 14:31:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/31131171.html
匿名

发表评论

匿名网友

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

确定