英文:
Convert json single element arrays to strings
问题
在Go语言中,我需要解析这个JSON:
{
"response": [
{
"message": [
"hello world"
],
"misc": [
{
"timestamp": [
"2017-06-28T05:52:39.347Z"
],
"server": [
"server-0101"
]
}
]
}
]
}
我想要在Go中得到一个对象,该对象不包含所有不必要的数组,而是只包含一个字符串。源JSON中每个数组中永远只有一个字符串。
所以,我想要得到的最终结果是这个JSON:
{
"response": {
"message": "hello world",
"misc": {
"timestamp": "2017-06-28T05:52:39.347Z",
"server": "server-0101"
}
}
}
或者在Go中等效的对象。
目前,我必须使用Response[0].Misc[0].Timestamp[0]
来访问数据,这看起来很奇怪。
英文:
In Go I have to parse this json:
{
"response": [
{
"message": [
"hello world"
],
"misc": [
{
"timestamp": [
"2017-06-28T05:52:39.347Z"
],
"server": [
"server-0101"
]
}
]
}
]
}
I'd like to get an object in Go that doesn't include all the unnecessary arrays of with a single string. The source json will never have more than one string in each array.
So the end result that I'd like to get would be this json:
{
"response": {
"message": "hello world",
"misc": {
"timestamp": "2017-06-28T05:52:39.347Z",
"server": "server-0101"
}
}
}
Or an equivalent object in Go.
Right now I have to use Response[0].Misc[0].Timestamp[0]
to access the data which seems weird.
答案1
得分: 1
你可以通过定义自己的MarshalJSON
或UnmarshalJSON
方法,覆盖json.Marshal
/json.Unmarshal
方法对结构体的默认行为。
这里有一个简化版本的需要解码的结构体的代码摘录。
type Response struct {
Message string `json:"message"`
}
// UnmarshalJSON覆盖了JSON解组方法的默认行为。
func (r *Response) UnmarshalJSON(data []byte) error {
auxResponse := &struct {
Message []string `json:"message"`
}{}
if err := json.Unmarshal(data, &auxResponse); err != nil {
return err
}
// 考虑在数组长度上添加一些检查 :)
r.Message = auxResponse.Message[0]
return nil
}
你可以在这里找到完整的工作示例。
我建议你阅读这篇有关使用Go语言进行自定义JSON编码/解码的有趣文章。
英文:
You can override the default behaviour of json.Marshal
/ json.Unmarshal
methods for a struct, by defining its own MarshalJSON
or UnmarshalJSON
properly.
Here there is an excerpt for the code of a simplified version of the struct you need to decode.
type Response struct {
Message string `json:"message"`
}
// UnmarshalJSON overrides the default behaviour for JSON unmarshal method.
func (r *Response) UnmarshalJSON(data []byte) error {
auxResponse := &struct {
Message []string `json:"message"`
}{}
if err := json.Unmarshal(data, &auxResponse); err != nil {
return err
}
// Consider to add some checks on array length :)
r.Message = auxResponse.Message[0]
return nil
}
You can access the full working example here.
I suggest you to read this interesting article about custom JSON encode/decode with golang.
答案2
得分: 0
我想在Go中获取一个对象,该对象不包含所有不必要的数组,只包含一个字符串。
一种困难的方法是手动解析JSON(编写自己的解析器)。
一种明智的方法是使用encoding/json包将其解组为与JSON匹配的某种Go类型,或解组为某种通用的interface{}
,然后将其复制到另一种更简单的Go类型中。
英文:
> I'd like to get an object in Go that doesn't include all the unnecessary arrays of with a single string.
The hard way: Parse the JSON by hand (write our own parser).
The sensible way: Unmarshal via package encoding/json into some Go type matching the JSON or into some generic interface{}
and copy the pieces into a different, simpler Go type afterwards.
答案3
得分: 0
创建自己的解码器可能是最好的方法,但这是一种模拟你想要实现的快速方式。
package main
import (
"encoding/json"
"fmt"
)
// JSON ...
var JSON = `{
"response": [
{
"message": [
"hello world"
],
"misc": [
{
"timestamp": [
"2017-06-28T05:52:39.347Z"
],
"server": [
"server-0101"
]
}
]
}
]
}`
type rawObject struct {
Response []struct {
Message []string `json:"message"`
Misc []interface{} `json:"misc"`
} `json:"response"`
}
type clean struct {
Message string `json:"message"`
Misc map[string]interface{} `json:"misc"`
}
func main() {
var o rawObject
var c clean
// 初始化 map
c.Misc = make(map[string]interface{})
// 解码原始数据
json.Unmarshal([]byte(JSON), &o)
for _, res := range o.Response { // 我假设只会有一个响应,不知道为什么要包装成数组
// 假设 message 实际上不是一个数组
c.Message = res.Message[0]
// 将 []interface 转换为 map[string]interface
for _, m := range res.Misc {
for k, v := range m.(map[string]interface{}) {
c.Misc[k] = v
}
}
}
fmt.Printf("%+v\n", c)
}
我不喜欢这个答案的原因是它不太可重用...所以可能应该创建一个函数并进行更多的错误检查(创建自定义解码器的一部分)。如果在大规模生产中使用,可能会遇到一些内存问题,因为我必须创建一个原始对象来创建一个 clean
对象...但作为一次性脚本,它能完成任务。我在 clean 结构体中没有添加 response 作为类型,因为我觉得这是多余的。
英文:
Creating your own unmarshaller is probably best, but this is a quick way to simulate what you want to achieve.
package main
import (
"encoding/json"
"fmt"
)
// JSON ...
var JSON = `{
"response": [
{
"message": [
"hello world"
],
"misc": [
{
"timestamp": [
"2017-06-28T05:52:39.347Z"
],
"server": [
"server-0101"
]
}
]
}
]
}
`
type rawObject struct {
Response []struct {
Message []string `json:"message"`
Misc []interface{} `json:"misc"`
} `json:"response"`
}
type clean struct {
Message string `json:"message"`
Misc map[string]interface{} `json:"misc"`
}
func main() {
var o rawObject
var c clean
// init map
c.Misc = make(map[string]interface{})
// unmarshall the raw data
json.Unmarshal([]byte(JSON), &o)
for _, res := range o.Response { // I assume there should only be one response, don't know why this is wrapped as an array
// assume message is not really an array
c.Message = res.Message[0]
// convert []interface to map[string]interface
for _, m := range res.Misc {
for k, v := range m.(map[string]interface{}) {
c.Misc[k] = v
}
}
}
fmt.Printf("%+v\n", c)
}
What i don't like about this answer is that it isn't very reusable..so a function should probably be made and more error checking (part of creating a custom unmarshaller). If this were used in heavy production it might run into some memory issues, as I have to create a raw object to create a clean
object.. but as a one off script it does the job. I my clean struct doesn't add response as a type because i find it to be redundant.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论