将 JSON 中的单元素数组转换为字符串。

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

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

你可以通过定义自己的MarshalJSONUnmarshalJSON方法,覆盖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.

huangapple
  • 本文由 发表于 2017年6月28日 16:10:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/44796996.html
匿名

发表评论

匿名网友

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

确定