我有一个示例 json,字段名称并不重要,但某些字段的嵌套值和数据类型很重要。我知道在 go 中,您必须确保在写入 csv 时,使用 csv.Writer 时数据是字符串数据类型。我的问题是,编写嵌套值的正确方法是什么,是否有一种有效的方法可以通过遍历整个 json 来转换所有非字符串值?
`{
"name":"Name1",
"id": 2,
"jobs":{
"job1":"somejob",
"job2":"somejob2"
},
"prevIds":{
"id1": 100,
"id2": 102
}
}`
Run Code Online (Sandbox Code Playgroud)
是例子json
一个工作示例如下:
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
}
}`)
Run Code Online (Sandbox Code Playgroud)
这通过解码任意 JSON 来工作,如这篇 goblog 文章所示,然后通过以通常的方式将其转换为字符串来迭代和处理每种可能的类型。如果您遇到 a map[string]interface{},那么您正在递归获取下一组数据。
一旦你有了一个[]string,你就可以把它传递给你csv.Writer,随心所欲地写出来。在这种情况下,输出是
Name1,2,somejob,somejob2,100,102
Run Code Online (Sandbox Code Playgroud)