No Values when Loading Json from File Golang - json

I hope someone could help me with this issue because I have been scratching my head for a while.
I have a project where I am trying to load json into a struct in go. I have followed exactly several tutorials online, but keep getting no data back and no error.
My json file is called page_data.json and looks like:
[
{
"page_title": "Page1",
"page_description": "Introduction",
"link": "example_link",
"authors":
[
"Author1",
"Author2",
"Author3",
]
},
// second object, same as the first
]
But when I try the following in go:
package main
import (
"fmt"
"encoding/json"
"os"
"io/ioutil"
)
type PageData struct {
Title string `json: "page_title"`
Description string `json: "page_description"`
Link string `json: "link"`
Authors []string `json: "authors"`
}
func main() {
var numPages int = LoadPageData("page_data.json")
fmt.Printf("Num Pages: %d", numPages)
}
func LoadPageData(path string) int {
jsonFile, err := os.Open(path)
if err != nil {
fmt.Println(err)
}
defer jsonFile.Close()
byteValue, _ := ioutil.ReadAll(jsonFile)
var pageList []PageData
json.Unmarshal(byteValue, &pageList)
return len(pageList)
}
the output I get is:
Num Pages: 0

Fix the JSON commas and the Go struct field tags. For example,
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
)
type PageData struct {
Title string `json:"page_title"`
Description string `json:"page_description"`
Link string `json:"link"`
Authors []string `json:"authors"`
}
func main() {
var numPages int = LoadPageData("page_data.json")
fmt.Printf("Num Pages: %d\n", numPages)
}
func LoadPageData(path string) int {
jsonFile, err := os.Open(path)
if err != nil {
fmt.Println(err)
}
defer jsonFile.Close()
byteValue, err := ioutil.ReadAll(jsonFile)
if err != nil {
fmt.Println(err)
}
var pageList []PageData
err = json.Unmarshal(byteValue, &pageList)
if err != nil {
fmt.Println(err)
}
fmt.Println(pageList)
return len(pageList)
}
Output:
[{Page1 Introduction example_link [Author1 Author2 Author3]}]
page_data.json:
[
{
"page_title": "Page1",
"page_description": "Introduction",
"link": "example_link",
"authors":
[
"Author1",
"Author2",
"Author3"
]
}
]

Related

loading static data into nested struct in Go

I am looking to implement something very similar to this GoPlayground example:
https://go.dev/play/p/B4JOVwgdwUk
However my data structure is a bit more complex, with the nested struct called Tag. I can't quite get the syntax correct for how to load the data into the struct in the toFile variable declaration.
Can someone help me figure out what I am doing wrong? I have tried what is displayed in the full code below, as well as this:
Tags: []Tag{
[{"appID:": "go", "category": "backend"},{"appID": "fiber", "category": "framework"}]
}
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
)
func main() {
type Stack struct {
Reputation int `json:"reputation"`
UserID int `json:"user_id"`
UserType string `json:"user_type"`
ProfileImage string `json:"profile_image"`
DisplayName string `json:"display_name"`
Link string `json:"link"`
Tags []Tag `json:"tags"`
}
type Tag struct {
AppID string `json: "appID:,omitempty"`
Category string `json: "category:,omitempty"`
}
toFile := Stack{
Reputation: 141,
UserID: 9820773,
UserType: "registered",
ProfileImage: "https://graph.facebook.com/10209865263541884/picture?type=large",
DisplayName: "Joe Smith",
Link: "https://stackoverflow.com/users/9820773/joe-smith",
Tags: Tag{
[{"appID:": "go", "category": "backend"},{"appID": "fiber", "category": "framework"}]
} // cannot get this to work
}
// Write it out!
tmpFile, err := ioutil.TempFile(os.TempDir(), "sample-")
if err != nil {
panic(err)
}
defer os.Remove(tmpFile.Name())
err = json.NewEncoder(tmpFile).Encode(toFile)
if err != nil {
panic(err)
}
err = tmpFile.Close()
if err != nil {
panic(err)
}
// Let's read it in!
tmpFile2, err := os.Open(tmpFile.Name())
if err != nil {
panic(err)
}
var fromFile Person
err = json.NewDecoder(tmpFile2).Decode(&fromFile)
if err != nil {
panic(err)
}
err = tmpFile2.Close()
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", fromFile)
}
The comment from #Kousik helped me fix up the code and run it successfully on the GoPlayground:
https://go.dev/play/p/WmZ9m_55W3S
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
)
func main() {
type Tag struct {
AppID string `json: "appID:,omitempty"`
Category string `json: "category:,omitempty"`
}
type Stack struct {
Reputation int `json:"reputation"`
UserID int `json:"user_id"`
UserType string `json:"user_type"`
ProfileImage string `json:"profile_image"`
DisplayName string `json:"display_name"`
Link string `json:"link"`
Tags []Tag `json:"tags"`
}
toFile := Stack{
Reputation: 141,
UserID: 9820773,
UserType: "registered",
ProfileImage: "https://graph.facebook.com/10209865263541884/picture?type=large",
DisplayName: "Joe Smith",
Link: "https://stackoverflow.com/users/9820773/joe-smith",
Tags: []Tag{{AppID: "id1", Category: "cat1"}, {AppID: "id2", Category: "cat2"}},
}
// Write it out!
tmpFile, err := ioutil.TempFile(os.TempDir(), "sample-")
if err != nil {
panic(err)
}
defer os.Remove(tmpFile.Name())
err = json.NewEncoder(tmpFile).Encode(toFile)
if err != nil {
panic(err)
}
err = tmpFile.Close()
if err != nil {
panic(err)
}
// Let's read it in!
tmpFile2, err := os.Open(tmpFile.Name())
if err != nil {
panic(err)
}
var fromFile Stack
err = json.NewDecoder(tmpFile2).Decode(&fromFile)
if err != nil {
panic(err)
}
err = tmpFile2.Close()
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", fromFile)
}

JSON unmarshal: all values are zero [duplicate]

I need to decode a JSON string with the float number like:
{"name":"Galaxy Nexus", "price":"3460.00"}
I use the Golang code below:
package main
import (
"encoding/json"
"fmt"
)
type Product struct {
Name string
Price float64
}
func main() {
s := `{"name":"Galaxy Nexus", "price":"3460.00"}`
var pro Product
err := json.Unmarshal([]byte(s), &pro)
if err == nil {
fmt.Printf("%+v\n", pro)
} else {
fmt.Println(err)
fmt.Printf("%+v\n", pro)
}
}
When I run it, get the result:
json: cannot unmarshal string into Go value of type float64
{Name:Galaxy Nexus Price:0}
I want to know how to decode the JSON string with type convert.
The answer is considerably less complicated. Just add tell the JSON interpeter it's a string encoded float64 with ,string (note that I only changed the Price definition):
package main
import (
"encoding/json"
"fmt"
)
type Product struct {
Name string
Price float64 `json:",string"`
}
func main() {
s := `{"name":"Galaxy Nexus", "price":"3460.00"}`
var pro Product
err := json.Unmarshal([]byte(s), &pro)
if err == nil {
fmt.Printf("%+v\n", pro)
} else {
fmt.Println(err)
fmt.Printf("%+v\n", pro)
}
}
Just letting you know that you can do this without Unmarshal and use json.decode. Here is Go Playground
package main
import (
"encoding/json"
"fmt"
"strings"
)
type Product struct {
Name string `json:"name"`
Price float64 `json:"price,string"`
}
func main() {
s := `{"name":"Galaxy Nexus","price":"3460.00"}`
var pro Product
err := json.NewDecoder(strings.NewReader(s)).Decode(&pro)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(pro)
}
Avoid converting a string to []byte: b := []byte(s). It allocates a new memory space and copy the whole the content into it.
strings.NewReader interface is better. Below is the code from godoc:
package main
import (
"encoding/json"
"fmt"
"io"
"log"
"strings"
)
func main() {
const jsonStream = `
{"Name": "Ed", "Text": "Knock knock."}
{"Name": "Sam", "Text": "Who's there?"}
{"Name": "Ed", "Text": "Go fmt."}
{"Name": "Sam", "Text": "Go fmt who?"}
{"Name": "Ed", "Text": "Go fmt yourself!"}
`
type Message struct {
Name, Text string
}
dec := json.NewDecoder(strings.NewReader(jsonStream))
for {
var m Message
if err := dec.Decode(&m); err == io.EOF {
break
} else if err != nil {
log.Fatal(err)
}
fmt.Printf("%s: %s\n", m.Name, m.Text)
}
}
Passing a value in quotation marks make that look like string. Change "price":"3460.00" to "price":3460.00 and everything works fine.
If you can't drop the quotations marks you have to parse it by yourself, using strconv.ParseFloat:
package main
import (
"encoding/json"
"fmt"
"strconv"
)
type Product struct {
Name string
Price string
PriceFloat float64
}
func main() {
s := `{"name":"Galaxy Nexus", "price":"3460.00"}`
var pro Product
err := json.Unmarshal([]byte(s), &pro)
if err == nil {
pro.PriceFloat, err = strconv.ParseFloat(pro.Price, 64)
if err != nil { fmt.Println(err) }
fmt.Printf("%+v\n", pro)
} else {
fmt.Println(err)
fmt.Printf("%+v\n", pro)
}
}

got an error when i tried to call the value with go lang

I just starting learn this Go Lang programming, and now i'm stuck with the [] things, I tried to create a blog using the Go Lang and i'm using a template, there's no problem with the template, it just I want to append a data that I got from json file.
If I just take the data and send it through the file it's already done, but the problem is when I tried to append the slug to the data (because the json file i got no slug url in it.
That's why I want to get the title of the post then make a slug with it, then
package main
import (
"encoding/json"
"fmt"
"github.com/gosimple/slug"
"html/template"
"io/ioutil"
"net/http"
"os"
)
type Blog struct {
Title string
Author string
Header string
}
type Posts struct {
Posts []Post `json:"posts"`
}
type Post struct {
Title string `json:"title"`
Author string `json:"author"`
Content string `json:"content"`
PublishDate string `json:"publishdate"`
Image string `json:"image"`
}
type BlogViewModel struct {
Blog Blog
Posts []Post
}
func loadFile(fileName string) (string, error) {
bytes, err := ioutil.ReadFile(fileName)
if err != nil {
return "", err
}
return string(bytes), nil
}
func loadPosts() []Post {
jsonFile, err := os.Open("source/posts.json")
if err != nil {
fmt.Println(err)
}
fmt.Println("Successfully open the json file")
defer jsonFile.Close()
bytes, _ := ioutil.ReadAll(jsonFile)
var post []Post
json.Unmarshal(bytes, &post)
return post
}
func handler(w http.ResponseWriter, r *http.Request) {
blog := Blog{Title: "asd", Author: "qwe", Header: "zxc"}
posts := loadPosts()
viewModel := BlogViewModel{Blog: blog, Posts: posts}
t, _ := template.ParseFiles("template/blog.html")
t.Execute(w, viewModel)
}
The error is show in the main function
func main() {
posts := loadPosts()
for i := 0; i < len(posts.Post); i++ { // it gives me this error posts.Post undefined (type []Post has no field or method Post)
fmt.Println("Title: " + posts.Post[i].Title)
}
// http.HandleFunc("/", handler)
// fs := http.FileServer(http.Dir("template"))
// http.Handle("/assets/css/", fs)
// http.Handle("/assets/js/", fs)
// http.Handle("/assets/fonts/", fs)
// http.Handle("/assets/images/", fs)
// http.Handle("/assets/media/", fs)
// fmt.Println(http.ListenAndServe(":9000", nil))
}
I already try to solved it a couple of hours but I hit the wall, I think it's possible but I just don't find the way, I don't know what is the good keyword to solve the problem.
And I don't if I already explain good enough or not. Please help me, thank you
This is the JSON file format
{
"posts": [
{
"title": "sapien ut nunc",
"author": "Jeni",
"content": "jgwilt0#mapquest.com",
"publishdate": "26.04.2017",
"image": "http://dummyimage.com/188x199.png/cc0000/ffffff"
},
{
"title": "mus vivamus vestibulum sagittis",
"author": "Analise",
"content": "adonnellan1#biblegateway.com",
"publishdate": "13.03.2017",
"image": "http://dummyimage.com/182x113.bmp/ff4444/ffffff"
}
]
}
You're loadPost method returns []Post. Your definition of Post does not contain the attribute Post. Your Posts struct does.
Here is a modified working example. I didn't define your other structures for brevity.
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
)
var rawJson = `{
"posts": [
{
"title": "sapien ut nunc",
"author": "Jeni",
"content": "jgwilt0#mapquest.com",
"publishdate": "26.04.2017",
"image": "http://dummyimage.com/188x199.png/cc0000/ffffff"
},
{
"title": "mus vivamus vestibulum sagittis",
"author": "Analise",
"content": "adonnellan1#biblegateway.com",
"publishdate": "13.03.2017",
"image": "http://dummyimage.com/182x113.bmp/ff4444/ffffff"
}
]
}`
type Data struct {
Posts []struct {
Title string `json:"title"`
Author string `json:"author"`
Content string `json:"content"`
Publishdate string `json:"publishdate"`
Image string `json:"image"`
} `json:"posts"`
}
func loadFile(fileName string) (string, error) {
bytes, err := ioutil.ReadFile(fileName)
if err != nil {
return "", err
}
return string(bytes), nil
}
func loadData() (Data, error) {
var d Data
// this is commented out so that i can load raw bytes as an example
/*
f, err := os.Open("source/posts.json")
if err != nil {
return d, err
}
defer f.Close()
bytes, _ := ioutil.ReadAll(f)
*/
// replace rawJson with bytes in prod
json.Unmarshal([]byte(rawJson), &d)
return d, nil
}
func main() {
data, err := loadData()
if err != nil {
log.Fatal(err)
}
for i := 0; i < len(data.Posts); i++ {
fmt.Println("Title: " + data.Posts[i].Title)
}
/*
// you can also range over the data.Posts if you are not modifying the data then using the index is not necessary.
for _, post := range data.Posts {
fmt.Println("Title: " + post.Title)
}
*/
}
modified just for files
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
)
type Data struct {
Posts []struct {
Title string `json:"title"`
Author string `json:"author"`
Content string `json:"content"`
Publishdate string `json:"publishdate"`
Image string `json:"image"`
} `json:"posts"`
}
func loadData() (Data, error) {
var d Data
b, err := ioutil.ReadFile("source/posts.json")
if err != nil {
return d, err
}
err = json.Unmarshal(b, &d)
if err != nil {
return d, err
}
return d, nil
}
func main() {
data, err := loadData()
if err != nil {
log.Fatal(err)
}
for _, post := range data.Posts {
fmt.Println("Title: " + post.Title)
}
}

Parsing a JSON file in Go

I am having trouble parsing a JSON file in Go.
I am not getting any errors, but I am not getting an output.
I have tried a few different methods, but I can't seem to get any to work.
Any help would be greatly appreciated. Thanks in advance.
package simplefiles
import (
"encoding/json"
"fmt"
"os"
)
//PluginInfo - struct for plugins.json
var PluginInfo struct {
LatestVersion string `json:"latest_version"`
LastUpdated string `json:"last_updated"`
Popular bool `json:"popular"`
Info []string `json:"Info"`
}
//ParsePlugins - parses plugins.json
func ParsePlugins() {
pluginsFile, err := os.Open("test.json")
if err != nil {
fmt.Println("opening config file", err.Error())
}
jsonParser := json.NewDecoder(pluginsFile)
if err = jsonParser.Decode(&PluginInfo); err != nil {
fmt.Println("parsing config file", err.Error())
} else {
fmt.Printf(PluginInfo.LastUpdated)
}
return
}
JSON Sample:
{
"my-test-site":{
"latest_version":"6.4.5",
"last_updated":"2016-05-22T00:23:00.000Z",
"popular":true,
"infomation":[
{
"id":6043,
"title":"Test info 1",
"created_at":"2014-08-01T10:58:35.000Z",
"updated_at":"2015-05-15T13:47:24.000Z",
"published_date":null,
"references":{
"url":[
"http://samplesite1.com",
"http://samplesite2.com"
]
},
"site_type":"info",
"fixed_v":"1.10"
}
]
},
"another-test-site":{
"latest_version":"2.1.0",
"last_updated":"2016-06-12T08:36:00.000Z",
"popular":false,
"infomation":[
{
"id":6044,
"title":"Test site 2 info",
"created_at":"2014-08-01T10:58:35.000Z",
"updated_at":"2015-05-15T13:47:24.000Z",
"published_date":null,
"references":{
"otherinfo":[
"blah blah blah"
]
},
"site_type":"search",
"fixed_v":"1.2.0"
}
]
}
}
Your problem is that your JSON data is a map of string to the struct type you defined, not the struct type directly. If you modify your code slightly as below it works, but you need to index into the map to get each struct value:
package main
import (
"encoding/json"
"fmt"
"os"
)
//PluginInfo - struct for plugins.json
var PluginInfo map[string]struct { // NOTICE map of string to struct
LatestVersion string `json:"latest_version"`
LastUpdated string `json:"last_updated"`
Popular bool `json:"popular"`
Info []string `json:"Info"`
}
//ParsePlugins - parses plugins.json
func ParsePlugins() {
pluginsFile, err := os.Open("test.json")
if err != nil {
fmt.Println("opening config file", err.Error())
}
jsonParser := json.NewDecoder(pluginsFile)
if err = jsonParser.Decode(&PluginInfo); err != nil {
fmt.Println("parsing config file", err.Error())
} else {
for key, val := range PluginInfo {
fmt.Printf("Key %q, last updated %s\n", key, val.LastUpdated)
}
}
return
}
func main() {
ParsePlugins()
}

How to decode JSON with type convert from string to float64

I need to decode a JSON string with the float number like:
{"name":"Galaxy Nexus", "price":"3460.00"}
I use the Golang code below:
package main
import (
"encoding/json"
"fmt"
)
type Product struct {
Name string
Price float64
}
func main() {
s := `{"name":"Galaxy Nexus", "price":"3460.00"}`
var pro Product
err := json.Unmarshal([]byte(s), &pro)
if err == nil {
fmt.Printf("%+v\n", pro)
} else {
fmt.Println(err)
fmt.Printf("%+v\n", pro)
}
}
When I run it, get the result:
json: cannot unmarshal string into Go value of type float64
{Name:Galaxy Nexus Price:0}
I want to know how to decode the JSON string with type convert.
The answer is considerably less complicated. Just add tell the JSON interpeter it's a string encoded float64 with ,string (note that I only changed the Price definition):
package main
import (
"encoding/json"
"fmt"
)
type Product struct {
Name string
Price float64 `json:",string"`
}
func main() {
s := `{"name":"Galaxy Nexus", "price":"3460.00"}`
var pro Product
err := json.Unmarshal([]byte(s), &pro)
if err == nil {
fmt.Printf("%+v\n", pro)
} else {
fmt.Println(err)
fmt.Printf("%+v\n", pro)
}
}
Just letting you know that you can do this without Unmarshal and use json.decode. Here is Go Playground
package main
import (
"encoding/json"
"fmt"
"strings"
)
type Product struct {
Name string `json:"name"`
Price float64 `json:"price,string"`
}
func main() {
s := `{"name":"Galaxy Nexus","price":"3460.00"}`
var pro Product
err := json.NewDecoder(strings.NewReader(s)).Decode(&pro)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(pro)
}
Avoid converting a string to []byte: b := []byte(s). It allocates a new memory space and copy the whole the content into it.
strings.NewReader interface is better. Below is the code from godoc:
package main
import (
"encoding/json"
"fmt"
"io"
"log"
"strings"
)
func main() {
const jsonStream = `
{"Name": "Ed", "Text": "Knock knock."}
{"Name": "Sam", "Text": "Who's there?"}
{"Name": "Ed", "Text": "Go fmt."}
{"Name": "Sam", "Text": "Go fmt who?"}
{"Name": "Ed", "Text": "Go fmt yourself!"}
`
type Message struct {
Name, Text string
}
dec := json.NewDecoder(strings.NewReader(jsonStream))
for {
var m Message
if err := dec.Decode(&m); err == io.EOF {
break
} else if err != nil {
log.Fatal(err)
}
fmt.Printf("%s: %s\n", m.Name, m.Text)
}
}
Passing a value in quotation marks make that look like string. Change "price":"3460.00" to "price":3460.00 and everything works fine.
If you can't drop the quotations marks you have to parse it by yourself, using strconv.ParseFloat:
package main
import (
"encoding/json"
"fmt"
"strconv"
)
type Product struct {
Name string
Price string
PriceFloat float64
}
func main() {
s := `{"name":"Galaxy Nexus", "price":"3460.00"}`
var pro Product
err := json.Unmarshal([]byte(s), &pro)
if err == nil {
pro.PriceFloat, err = strconv.ParseFloat(pro.Price, 64)
if err != nil { fmt.Println(err) }
fmt.Printf("%+v\n", pro)
} else {
fmt.Println(err)
fmt.Printf("%+v\n", pro)
}
}