Reputation: 2290
I have a JSON file of the form:
{
"data": {
"docs": [
{"key00": "val00", "key01": "val01"},
{"key10": "val10", "key11": "val11"}
]
}
}
and I would like to convert it to separate JSON docs:
{
{"key00": "val00", "key01": "val01"}
}
{
{"key10": "val10", "key11": "val11"}
}
I can enumerate over the array contents using:
j, _ := ioutil.ReadFile(path)
dec, _ := simplejson.NewFromReader(bytes.NewReader(j))
for i,v := range dec.Get("data").Get("docs").MustArray() {
out := simplejson.New()
/* ??? move dec key/value pairs to out ??? */
b, _ := out.EncodePretty()
ioutil.WriteFile(outpath, b, 0777)
}
but I'm not sure how to iterate over the key/value pairs within the array entries. It's a nice, succinct library but there don't appear to be a lot of examples and my golang expertise is currently limited.
Any help would be appreciated.. thanks!
Upvotes: 3
Views: 2320
Reputation: 711
Is there any specific reason to use simplejson? A lot of encoding can be done with the standard JSON library.
Using the standard library you could solve your problem like this:
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
)
type Document struct {
Data DataStruct
}
type DataStruct struct {
Docs []interface{}
}
func main() {
doc, err := ioutil.ReadFile("./doc.json")
if err != nil {
panic(err)
}
var document Document
err = json.Unmarshal(doc, &document)
if err != nil {
panic(err)
}
for index := range document.Data.Docs {
b, err := json.Marshal(document.Data.Docs[index])
if err != nil {
panic(err)
}
err = ioutil.WriteFile(fmt.Sprintf("file%d.json", index), b, 0777)
if err != nil {
panic(err)
}
fmt.Println(string(b))
}
}
The sample code will provide you two files with contents like this:
{"key00":"val00","key01":"val01"}
and
{"key10":"val10","key11":"val11"}
However, if you noticed I used the []interface{} notation in the DataStruct, which in general is considered bad practice. You should create a new structure with proper type declarations if your real-world data has any.
Upvotes: 1
Reputation: 99215
You can use simplejson.Set
:
for _, doc := range dec.Get("data").Get("docs").MustArray() {
out := simplejson.New()
// doc is an interface{} holding a map, we have to type assert it.
for k, v := range doc.(map[string]interface{}) {
out.Set(k, v)
}
b, _ := out.EncodePretty()
fmt.Printf("%s\n", b)
}
However in that instance, simplejson is an overkill and using a struct / stdlib is more efficient.
For completeness sake, the std lib version:
type DataLayout struct {
Data struct {
Docs []map[string]string `json:"docs"`
} `json:"data"`
}
func main() {
var in DataLayout
err := json.NewDecoder(strings.NewReader(j)).Decode(&in)
if err != nil {
log.Fatal(err)
}
for _, doc := range in.Data.Docs {
b, err := json.MarshalIndent(doc, "", "\t")
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", b)
}
}
Notes:
"key10", "val10"
should be "key10": "val10"
.fmt.Printf("%#v", doc)
to see how it looks like. Upvotes: 2