首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >golang unmarshal complex json

golang unmarshal complex json
EN

Stack Overflow用户
提问于 2015-06-30 04:08:43
回答 3查看 5.2K关注 0票数 3

我有以下JSON blob,我正在尝试将其解码为Go。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
["contig", "32", {"a":[33,41,35], "b":[44,34,42]}]

我认为我必须对JSON的数据结构进行建模。我尝试使用一个名为Line的结构

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (
"encoding/json"
"fmt"
)

type Line struct {
    Contig string
    Base   string
    PopMap map[string][]int
}

func main() {
    j := []byte(`["contig", "32", {"a":[33,41,35], "b":[44,34,42]}]`)
    var dat Line
    err := json.Unmarshal(j, &dat)
    fmt.Println(dat)
    fmt.Println(err)
}

我得到了以下错误:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{  map[]}
json: cannot unmarshal array into Go value of type main.Line

我做错了什么?

Link to sandbox for trying out code

EN

回答 3

Stack Overflow用户

发布于 2015-06-30 06:21:12

您指定的JSON输入是一个不同类型的数组,因此,您不能将其解组为struct,只能将其解组为不同类型的片:[]interface{}

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
in := `["contig", "32", {"a":[33,41,35], "b":[44,34,42]}]`

var arr []interface{}
if err := json.Unmarshal([]byte(in), &arr); err != nil {
    panic(err)
}
fmt.Println(arr)

输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[contig 32 map[a:[33 41 35] b:[44 34 42]]]

填写struct

很好,您现在有了这些值,只是不是在您想要的struct中。您可以使用type assertion获取所需的类型:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
l := Line{PopMap: map[string][]int{}}
l.Contig = arr[0].(string)
l.Base = arr[1].(string)

m := arr[2].(map[string]interface{})
for k, v := range m {
    nums := v.([]interface{})
    pops := make([]int, len(nums))
    for i, val := range nums {
        pops[i] = int(val.(float64))
    }
    l.PopMap[k] = pops
}

fmt.Printf("%+v", l)

输出(在Go Playground上试用):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{Contig:contig Base:32 PopMap:map[a:[33 41 35] b:[44 34 42]]}

一些注意事项:

"a""b"的值的“内部”数组被解组为[]interface{}类型的值,您不能简单地将其转换为[]int[]float64,因此for循环迭代它们并在它们的每个元素上使用类型断言。还要注意,json包将数字解组为float64类型的值,而不是int类型的值(因为不只是整数可以包含在JSON文本中,所以使用了float64,它可以同时容纳这两种类型)。

还要注意,在上面的示例中没有检查类型断言的成功。如果未封送的数组的元素少于3个,或者任何类型断言失败,则会发生运行时死机。

使用recover()

您可以添加一个调用recover()defer函数来捕获这种死机(在Go Playground上尝试一下):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
defer func() {
    if r := recover(); r != nil {
        fmt.Println("Failed to unmarshal")
    }
}()

l := Line{PopMap: map[string][]int{}}
// ...and here comes the code that uses type assertions
// and stores values into...

带检查的代码

或者您可以添加对类型断言的检查。类型断言有一种特殊的v, ok = x.(T)格式,在使用时不会出现异常,但如果类型断言不成立,ok将为false (如果类型断言成立,则为true )。

Go Playground上试用一下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if len(arr) < 3 {
    return
}
var ok bool
l := Line{PopMap: map[string][]int{}}
if l.Contig, ok = arr[0].(string); !ok {
    return
}
if l.Base, ok = arr[1].(string); !ok {
    return
}
if m, ok := arr[2].(map[string]interface{}); !ok {
    return
} else {
    for k, v := range m {
        var nums []interface{}
        if nums, ok = v.([]interface{}); !ok {
            return
        }
        pops := make([]int, len(nums))
        for i, val := range nums {
            if f, ok := val.(float64); !ok {
                return
            } else {
                pops[i] = int(f)
            }
        }
        l.PopMap[k] = pops
    }
}

fmt.Printf("%+v", l)
票数 7
EN

Stack Overflow用户

发布于 2015-06-30 04:39:00

因为您拥有的是数组文字而不是对象,所以解析的最佳方法是首先解组到json.RawMessages的片段,然后遍历结果片段中的字段:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (
     "encoding/json"
     "fmt"
)


func main() {
    j := []byte(`["contig", "32", {"a":[33,41,35], "b":[44,34,42]}]`)

    var entries []json.RawMessage
    err := json.Unmarshal(j, &entries)
    if err != nil {
        fmt.Println(err)
    }

    var contig string
    var num string
    var obj struct {
        A []int `json:"a"`
        B []int `json:"b"`
    }

    err = json.Unmarshal(entries[0], &contig)
    err = json.Unmarshal(entries[1], &num)
    err = json.Unmarshal(entries[2], &obj)

    fmt.Println(contig)
    fmt.Println(num)
    fmt.Println(obj)
}

这会给出正确的结果:

contig 32 {[33 41 35] [44 34 42]}

游乐场:https://play.golang.org/p/jcYvINkTTn

但是,如果您可以控制JSON的源代码,那么将其更改为对象文字将是最直接的方法。

票数 2
EN

Stack Overflow用户

发布于 2015-06-30 04:29:29

您的JSON包含一个数组文字,而您正试图将其反序列化为结构。您需要将JSON更改为对象文字,其中键是结构的属性名称。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
j := []byte(`{
    "Contig": "contig",
    "Base": "32",
    "PopMap": {"a":[33,41,35], "b":[44,34,42]}
}`)

如果您无法更改JSON,则需要将其反序列化为无类型数组,并将其转换为结构类型。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31129379

复制
相关文章
【HTML】HTML 表单 ② ( 按钮表单 | 普通按钮 | 提交按钮 | 重置按钮 | 图片按钮 | 文件域 )
将 <input /> 标签 的 type 属性设置为 button , 就可以将该 表单组件 设置为 普通按钮 类型表单 ;
韩曙亮
2023/03/30
8.2K0
【HTML】HTML 表单 ② ( 按钮表单 | 普通按钮 | 提交按钮 | 重置按钮 | 图片按钮 | 文件域 )
Html动态点击按钮实现“+”和“-”功能
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/147257.html原文链接:https://javaforall.cn
全栈程序员站长
2022/07/01
3.8K0
Html动态点击按钮实现“+”和“-”功能
html.dropdownlistfor_html按钮样式
var parents = _MemberEditDTOService.GetParents();
全栈程序员站长
2022/09/27
4.6K0
gridlayout java_Java GridLayout
GridLayout(int rows, int columns, int hgap, int vgap)
全栈程序员站长
2022/07/01
2920
gridlayout java_Java GridLayout
android gridlayout点击事件,Android GridLayout
当组件需要的空间超出你预期的时候会跑出屏幕或发生重叠因为你不能使用weight等等
全栈程序员站长
2022/08/12
1K0
android gridlayout点击事件,Android GridLayout
GridLayout的使用
GridLayout比FlowLayout多了行和列的设置,也就是说你要先设置GridLayout共有几行几列,就如同二维平面一般,然后你加 进去的组件会先填第一行的格子,然后再从第二行开始填,依此类扒,就像是一个个的格子一般。而且GridLayout会将所填进去组 件的大小设为一样。
全栈程序员站长
2022/07/01
2880
仅使用HTML和CSS的亮暗模式按钮切换
我的目标之一是使每个工具都可以不使用javascript,以一定程度上简化代码,同时也是个挑战。
鲸落c
2022/11/14
4K0
仅使用HTML和CSS的亮暗模式按钮切换
仅使用HTML和CSS的亮暗模式按钮切换
我的目标之一是使每个工具都可以不使用javascript,以一定程度上简化代码,同时也是个挑战。
海拥
2021/08/23
3.3K0
仅使用HTML和CSS的亮暗模式按钮切换
IDEA GridLayout
其中注意GridLayout的声明成MainActivity的成员,不能在成员函数内声明(我在这检查了半天),还有xml中第二个TextView的android:layout_columnSpan=”4”不能省略,不然下面的“LLL”就只有一列。
全栈程序员站长
2022/07/01
3520
IDEA GridLayout
GridLayout详解
GridLayout是一个非常强大的布局管理器,它可以实现很多复杂的布局,名字中暗示它将所有控件放置在类似网格的布局中.^__^GridLayout有两个构造函数.
全栈程序员站长
2022/09/06
6950
gridlayout布局
android layout button encoding 框架 编程
全栈程序员站长
2022/09/05
5620
炫彩流光按钮 CSS + HTML
炫彩流光按钮 写在前面 你若要喜爱你自己的价值,你就得给世界创造价值。——歌德 效果图 三个绝美的样例 HTML代码 <div class="box"> <button clas
小丞同学
2021/08/16
3.8K0
java swt gridlayout_SWT GridLayout使用总结
里面所有方法都是链式调用,设置完GridLayout的参数后,调用applayTo::Composite,为一个Composite设置layout。Composite comp1 = toolkit.createComposite(shell);
全栈程序员站长
2022/09/02
7150
java swt gridlayout_SWT GridLayout使用总结
html点击按钮拨打电话
在进行移动版开发过程中,有时候页面上会留下商家的电话,用户点击电话或者电话旁边的小电话图标即可实现拨打电话的功能,这样省却了用户拨号的麻烦。下面我来介绍一下如何在html页面上点击调出拨打电话功能。
OECOM
2020/07/01
4.3K0
PyQt5--GridLayout
1 # -*- coding:utf-8 -*- 2 ''' 3 Created on Sep 13, 2018 4 5 @author: SaShuangYiBing 6 ''' 7 import sys 8 from PyQt5.QtWidgets import QApplication,QWidget,QPushButton,QGridLayout 9 10 class New_test(QWidget): 11 def __init__(self): 12
py3study
2020/01/19
4960
PyQt5--GridLayout
带有Vagrant和Virtualbox的Elasticsearch集群
模拟分布式存储和计算环境的一种简单方法是将Virtualbox作为VM(“虚拟机”)的提供者,将Vagrant作为配置,启动和停止这些VM的前端脚本引擎。这篇文章的目标是构建一个集群虚拟设备,将Elasticsearch作为可由主机使用/控制的服务提供。可以从Github下载本文中使用的工件。
February
2018/11/26
1.5K0
点击加载更多

相似问题

c#从字节数组创建xml

40

如何从字符串创建字节(数组)?

12

何时在Go中使用[]字节或字符串?

34

从字节数组创建字符串

33

Go,从字节数组中提取天数

20
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文