Joe Bergevin
Joe Bergevin

Reputation: 3268

Write Struct to Json File using Struct Fields (not json keys)

How can I read a json file into a struct, and then Marshal it back out to a json string with the Struct fields as keys (rather than the original json keys)?

(see Desired Output to Json File below...)

Code:

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
)

type Rankings struct {
    Keyword  string `json:"keyword"`
    GetCount uint32 `json:"get_count"`
    Engine   string `json:"engine"`
    Locale   string `json:"locale"`
    Mobile   bool   `json:"mobile"`
}

func main() {
    var jsonBlob = []byte(`
        {"keyword":"hipaa compliance form", "get_count":157, "engine":"google", "locale":"en-us", "mobile":false}
    `)
    rankings := Rankings{}
    err := json.Unmarshal(jsonBlob, &rankings)
    if err != nil {
        // nozzle.printError("opening config file", err.Error())
    }

    rankingsJson, _ := json.Marshal(rankings)
    err = ioutil.WriteFile("output.json", rankingsJson, 0644)
    fmt.Printf("%+v", rankings)
}

Output on screen:

{Keyword:hipaa compliance form GetCount:157 Engine:google Locale:en-us Mobile:false}

Output to Json File:

{"keyword":"hipaa compliance form","get_count":157,"engine":"google","locale":"en-us","mobile":false}

Desired Output to Json File:

{"Keyword":"hipaa compliance form","GetCount":157,"Engine":"google","Locale":"en-us","Mobile":false}

Upvotes: 23

Views: 63892

Answers (3)

accnameowl
accnameowl

Reputation: 21

An accourance happened by just using json.Marshal() / json.MarshalIndent(). It overwrites the existing file, which in my case was suboptimal. I just wanted to add content to current file, and keep old content.

This writes data through a buffer, with bytes.Buffer type.

This is what I gathered up so far:

package srf

import (
    "bytes"
    "encoding/json"
    "os"
)

func WriteDataToFileAsJSON(data interface{}, filedir string) (int, error) {
    //write data as buffer to json encoder
    buffer := new(bytes.Buffer)
    encoder := json.NewEncoder(buffer)
    encoder.SetIndent("", "\t")

    err := encoder.Encode(data)
    if err != nil {
        return 0, err
    }
    file, err := os.OpenFile(filedir, os.O_RDWR|os.O_CREATE, 0755)
    if err != nil {
        return 0, err
    }
    n, err := file.Write(buffer.Bytes())
    if err != nil {
        return 0, err
    }
    return n, nil
}

This is the execution of the function, together with the standard json.Marshal() or json.MarshalIndent() which overwrites the file

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"

    minerals "./minerals"
    srf "./srf"
)

func main() {

    //array of Test struct
    var SomeType [10]minerals.Test

    //Create 10 units of some random data to write
    for a := 0; a < 10; a++ {
        SomeType[a] = minerals.Test{
            Name:   "Rand",
            Id:     123,
            A:      "desc",
            Num:    999,
            Link:   "somelink",
            People: []string{"John Doe", "Aby Daby"},
        }
    }

    //writes aditional data to existing file, or creates a new file
    n, err := srf.WriteDataToFileAsJSON(SomeType, "test2.json")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("srf printed ", n, " bytes to ", "test2.json")

    //overrides previous file
    b, _ := json.MarshalIndent(SomeType, "", "\t")
    ioutil.WriteFile("test.json", b, 0644)

}

Why is this useful? File.Write() returns bytes written to the file! So this is perfect if you want to manage memory or storage.

WriteDataToFileAsJSON() (numberOfBytesWritten, error)

Upvotes: 1

boulavard
boulavard

Reputation: 11

Try to change the json format in the struct

type Rankings struct {
    Keyword  string `json:"Keyword"`
    GetCount uint32 `json:"Get_count"`
    Engine   string `json:"Engine"`
    Locale   string `json:"Locale"`
    Mobile   bool   `json:"Mobile"`
}

Upvotes: 1

Momer
Momer

Reputation: 3237

If I understand your question correctly, all you want to do is remove the json tags from your struct definition.

So:

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
)

type Rankings struct {
    Keyword  string 
    GetCount uint32 
    Engine   string 
    Locale   string 
    Mobile   bool   
}

func main() {
    var jsonBlob = []byte(`
        {"keyword":"hipaa compliance form", "get_count":157, "engine":"google", "locale":"en-us", "mobile":false}
    `)
    rankings := Rankings{}
    err := json.Unmarshal(jsonBlob, &rankings)
    if err != nil {
        // nozzle.printError("opening config file", err.Error())
    }

    rankingsJson, _ := json.Marshal(rankings)
    err = ioutil.WriteFile("output.json", rankingsJson, 0644)
    fmt.Printf("%+v", rankings)
}

Results in:

{Keyword:hipaa compliance form GetCount:0 Engine:google Locale:en-us Mobile:false}

And the file output is:

{"Keyword":"hipaa compliance form","GetCount":0,"Engine":"google","Locale":"    en-us","Mobile":false}

Running example at http://play.golang.org/p/dC3s37HxvZ

Note: GetCount shows 0, since it was read in as "get_count". If you want to read in JSON that has "get_count" vs. "GetCount", but output "GetCount" then you'll have to do some additional parsing.

See Go- Copy all common fields between structs for additional info about this particular situation.

Upvotes: 34

Related Questions