将嵌套的JSON转换为CSV在GO中的实现

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

Converting nested JSON to csv in GO

问题

我有一个示例的 JSON 数据,字段名称并不重要,但是嵌套的值和某些字段的数据类型是重要的。我了解在 Go 语言中,当你使用 csv.Writer 写入 CSV 数据时,必须确保数据是字符串类型。我的问题是,如何正确地写入嵌套的值,并且是否有一种高效的方法通过迭代整个 JSON 数据将所有非字符串值转换为字符串?

示例的 JSON 数据如下:

{
  "name": "Name1",
  "id": 2,
  "jobs": {
    "job1": "somejob",
    "job2": "somejob2"
  },
  "prevIds": {
    "id1": 100,
    "id2": 102
  }
}
英文:

I have an example json, the field names aren't really important but the nested values and the data types of some fields are. I understand that in go you have to make sure that when you write to a csv, the data is a string data type when you use csv.Writer. My question is, whats the proper way of writing the nested values, and is there an efficient way to convert all non-string values by iterating through the overall json?

`{
  "name":"Name1",
  "id": 2,
  "jobs":{
      "job1":"somejob",
      "job2":"somejob2"
   },
  "prevIds":{
      "id1": 100,
      "id2": 102
  }
}`

Is the example json

答案1

得分: 7

以下是一个工作示例:

package main

import (
	"encoding/csv"
	"encoding/json"
	"fmt"
	"log"
	"os"
	"strconv"
)

func decodeJson(m map[string]interface{}) []string {
	values := make([]string, 0, len(m))
	for _, v := range m {
		switch vv := v.(type) {
		case map[string]interface{}:
			for _, value := range decodeJson(vv) {
				values = append(values, value)
			}
		case string:
			values = append(values, vv)
		case float64:
			values = append(values, strconv.FormatFloat(vv, 'f', -1, 64))
		case []interface{}:
			// 由于您没有指示我们应该处理数组,并且这样做并不容易,所以目前不处理数组。
		case bool:
			values = append(values, strconv.FormatBool(vv))
		case nil:
			values = append(values, "nil")
		}
	}
	return values
}

func main() {
	var d interface{}
	err := json.Unmarshal(exampleJSON, &d)
	if err != nil {
		log.Fatal("解析失败")
	}
	values := decodeJson(d.(map[string]interface{}))
	fmt.Println(values)

	f, err := os.Create("outputfile.csv")
	if err != nil {
		log.Fatal("创建 outputfile.csv 失败")
	}
	defer f.Close()
	w := csv.NewWriter(f)
	if err := w.Write(values); err != nil {
		log.Fatal("写入文件失败")
	}
	w.Flush()
	if err := w.Error(); err != nil {
		log.Fatal("刷新 outputfile.csv 失败")
	}
}

var exampleJSON []byte = []byte(`{
  "name":"Name1",
  "id": 2,
  "jobs":{
      "job1":"somejob",
      "job2":"somejob2"
   },
  "prevIds":{
      "id1": 100,
      "id2": 102
  }
}`)

这个示例通过解码任意的 JSON(如 这篇 Go 博客文章 中所示),然后迭代和处理每种可能的类型,将其转换为字符串。如果遇到 map[string]interface{},则会递归获取下一组数据。

一旦获得了 []string,您可以将其传递给 csv.Writer,以任何您喜欢的方式进行写入。在这个示例中,输出结果为:

Name1,2,somejob,somejob2,100,102
英文:

A working example is below:

package main
import (
"encoding/csv"
"encoding/json"
"fmt"
"log"
"os"
"strconv"
)
func decodeJson(m map[string]interface{}) []string {
values := make([]string, 0, len(m))
for _, v := range m {
switch vv := v.(type) {
case map[string]interface{}:
for _, value := range decodeJson(vv) {
values = append(values, value)
}
case string:
values = append(values, vv)
case float64:
values = append(values, strconv.FormatFloat(vv, 'f', -1, 64))
case []interface{}:
// Arrays aren't currently handled, since you haven't indicated that we should
// and it's non-trivial to do so.
case bool:
values = append(values, strconv.FormatBool(vv))
case nil:
values = append(values, "nil")
}
}
return values
}
func main() {
var d interface{}
err := json.Unmarshal(exampleJSON, &d)
if err != nil {
log.Fatal("Failed to unmarshal")
}
values := decodeJson(d.(map[string]interface{}))
fmt.Println(values)
f, err := os.Create("outputfile.csv")
if err != nil {
log.Fatal("Failed to create outputfile.csv")
}
defer f.Close()
w := csv.NewWriter(f)
if err := w.Write(values); err != nil {
log.Fatal("Failed to write to file")
}
w.Flush()
if err := w.Error(); err != nil {
log.Fatal("Failed to flush outputfile.csv")
}
}
var exampleJSON []byte = []byte(`{
"name":"Name1",
"id": 2,
"jobs":{
"job1":"somejob",
"job2":"somejob2"
},
"prevIds":{
"id1": 100,
"id2": 102
}
}`)

This works by decoding the arbitrary JSON as shown in this goblog post then iterating and handling each possible type by converting it to string in the usual way. If you come across a map[string]interface{}, then you're recursing to get the next set of data.

Once you've got a []string, you can pass it to your csv.Writer to write out however you like. In this case the output is

Name1,2,somejob,somejob2,100,102

huangapple
  • 本文由 发表于 2016年4月21日 02:21:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/36752050.html
匿名

发表评论

匿名网友

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

确定