Go Struct JSON数组的数组

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

Go Struct JSON array of arrays

问题

我正在尝试从特定的请求响应中映射一些数据,但在seriesLabels中有一些没有属性名称的数据(int,string),所以我对如何映射这些数据感到困惑:

这是服务的响应:

{
"data": {
"seriesLabels": [
[
0,
"(none)"
],
[
0,
"Cerveza"
],
[
0,
"Cigarros"
],
[
0,
"Tecate"
],
[
0,
"Cafe"
],
[
0,
"Amstel"
],
[
0,
"Leche"
],
[
0,
"Ultra"
],
[
0,
"Coca cola"
],
[
0,
"Agua"
]
]
}
}

我用以下go结构体来映射这些信息:

type PopularWord struct {
Data *Data json:"data"
}

type Data struct {
SeriesLabels []*SeriesLabels json:"seriesLabels"
}

type SeriesLabels struct {
value int32 json:""
name string json:""
}

我做错了什么?声明结构体的正确方式是什么?

英文:

I´m having problems trying to mapping some data from specific Request Response because inside seriesLabels: there are data without property names (int,string) so I'm confused how to map that data:

This is the service response:

{
"data": {
    "seriesLabels": [
        [
            0,
            "(none)"
        ],
        [
            0,
            "Cerveza"
        ],
        [
            0,
            "Cigarros"
        ],
        [
            0,
            "Tecate"
        ],
        [
            0,
            "Cafe"
        ],
        [
            0,
            "Amstel"
        ],
        [
            0,
            "Leche"
        ],
        [
            0,
            "Ultra"
        ],
        [
            0,
            "Coca cola"
        ],
        [
            0,
            "Agua"
        ]
    ]
}
}

My go struct to map that info is:

type PopularWord struct {
    Data *Data `json:"data"`
}

type Data struct {
    SeriesLabels []*SeriesLabels `json:"seriesLabels"`
}

type SeriesLabels struct {
    value int32  `json:""`
    name  string `json:""`
}

What am I doing wrong? What is the correct way to declare the structs?

答案1

得分: 2

问题是SeriesLabels在JSON中表示为一个数组。如果你想使用encoding/json,你需要实现Unmarshaler接口来解码它(否则它只会接受JSON对象)。

幸运的是,代码很简单:

func (s *SeriesLabels) UnmarshalJSON(d []byte) error {
    arr := []interface{}{&s.value, &s.name}
    return json.Unmarshal(d, &arr)
}

请注意,此代码忽略了无效的输入(数组过长或类型不正确)。根据你的需求,你可能希望在调用json.Unmarshal之后添加检查,确保数组的长度和内容(指针)没有改变。

Go还有其他一些JSON解析库,可以使这个过程更加简便,比如gojay

英文:

The problem is that SeriesLabels is represented in JSON as an array. If you want to use encoding/json, you have to implement the Unmarshaler interface to decode it (otherwise it will only accept JSON objects).

Fortunately, the code is simple:

func (s *SeriesLabels) UnmarshalJSON(d []byte) error {
	arr := []interface{}{&s.value, &s.name}
	return json.Unmarshal(d, &arr)
}

Note that this code ignores invalid input (array too long, or incorrect type). Depending on your needs, you may wish to add checks after the call to json.Unmarshal that the array length and contents (pointers) have not changed.

There are other JSON parsing libraries for Go that make this a bit less cumbersome, like gojay.

答案2

得分: 2

seriesLabels 是一个 JSON 数组,其元素也是 JSON 数组。

要解析一个 JSON 数组的数组,你可以在 Go 中使用切片的切片:

type Data struct {
    SeriesLabels [][]interface{}
}

测试代码

var pw *PopularWord
if err := json.Unmarshal([]byte(src), &pw); err != nil {
    panic(err)
}
fmt.Println(pw)
for _, sl := range pw.Data.SeriesLabels {
    fmt.Println(sl)
}

输出结果(在 [Go Playground][1] 上尝试):

&{0xc000120108}
[0 (none)]
[0 Cerveza]
[0 Cigarros]
[0 Tecate]
[0 Cafe]
[0 Amstel]
[0 Leche]
[0 Ultra]
[0 Coca cola]
[0 Agua]

要将内部数组作为结构值获取,你可以实现自定义的解组:

type Data struct {
    SeriesLabels []*SeriesLabels `json:"seriesLabels"`
}

type SeriesLabels struct {
    value int32
    name  string
}

func (sl *SeriesLabels) UnmarshalJSON(p []byte) error {
    var s []interface{}
    if err := json.Unmarshal(p, &s); err != nil {
        return err
    }
    if len(s) > 0 {
        if f, ok := s[0].(float64); ok {
            sl.value = int32(f)
        }
    }

    if len(s) > 1 {
        if s, ok := s[1].(string); ok {
            sl.name = s
        }
    }
    return nil
}

测试代码与之前相同输出结果 [Go Playground][2] 上尝试):

&{0xc0000aa0f0}
&{0 (none)}
&{0 Cerveza}
&{0 Cigarros}
&{0 Tecate}
&{0 Cafe}
&{0 Amstel}
&{0 Leche}
&{0 Ultra}
&{0 Coca cola}
&{0 Agua}


  [1]: https://play.golang.org/p/4slLP6So4Jv
  [2]: https://play.golang.org/p/iVL-lH46Mer

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

`seriesLabels` is a JSON array, and its elements are also JSON arrays.

To parse a JSON array of arrays, you may use a slice of slices in Go:

    type Data struct {
    	SeriesLabels [][]interface{}
    }

Testing it:

	var pw *PopularWord
	if err := json.Unmarshal([]byte(src), &amp;pw); err != nil {
		panic(err)
	}
	fmt.Println(pw)
	for _, sl := range pw.Data.SeriesLabels {
		fmt.Println(sl)
	}

Output (try it on the [Go Playground][1]):

    &amp;{0xc000120108}
    [0 (none)]
    [0 Cerveza]
    [0 Cigarros]
    [0 Tecate]
    [0 Cafe]
    [0 Amstel]
    [0 Leche]
    [0 Ultra]
    [0 Coca cola]
    [0 Agua]

To get the inner arrays as struct values, you may implement custom unmarshaling:

    type Data struct {
    	SeriesLabels []*SeriesLabels `json:&quot;seriesLabels&quot;`
    }
    
    type SeriesLabels struct {
    	value int32 
    	name  string
    }
    
    func (sl *SeriesLabels) UnmarshalJSON(p []byte) error {
    	var s []interface{}
    	if err := json.Unmarshal(p, &amp;s); err != nil {
    		return err
    	}
    	if len(s) &gt; 0 {
    		if f, ok := s[0].(float64); ok {
    			sl.value = int32(f)
    		}
    	}
    
    	if len(s) &gt; 1 {
    		if s, ok := s[1].(string); ok {
    			sl.name = s
    		}
    	}
    	return nil
    }

Testing code is the same, output (try this one on the [Go Playground][2]):

    &amp;{0xc0000aa0f0}
    &amp;{0 (none)}
    &amp;{0 Cerveza}
    &amp;{0 Cigarros}
    &amp;{0 Tecate}
    &amp;{0 Cafe}
    &amp;{0 Amstel}
    &amp;{0 Leche}
    &amp;{0 Ultra}
    &amp;{0 Coca cola}
    &amp;{0 Agua}


  [1]: https://play.golang.org/p/4slLP6So4Jv
  [2]: https://play.golang.org/p/iVL-lH46Mer

</details>



huangapple
  • 本文由 发表于 2021年8月4日 01:13:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/68640253.html
匿名

发表评论

匿名网友

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

确定