How to print the specific in an HTML file using golang? - html

In this code, I want to use and give a specific detail in the HTML file like heading or price.
The problem is that, there are multiple headings and prices and when I print the specific one, it prints the specific data successfully but I don't know how to use it in an HTML file to print the specific data there. All I know about GOHTML is {{.Heading}} but it does not work. Is there any other way?
package main
import "net/http"
type Details struct {
Heading string
Price string
}
var Detail = []Details{
{
Heading: "First Cloth",
Price: "$59",
},
{
Heading: "Second Cloth",
Price: "$49",
},
}
func Main(w http.ResponseWriter, r *http.Request) {
HomeTmpl.Execute(w, Detail)
// fmt.Println(Detail[1].Heading) // For specific data
}

You may use the builtin index template function to get an element from a slice:
{{ (index . 1).Heading }}
Testing it:
t := template.Must(template.New("").Parse(`{{ (index . 1).Heading }}`))
if err := t.Execute(os.Stdout, Detail); err != nil {
panic(err)
}
Which outputs (try it on the Go Playground):
Second Cloth

Related

How to correct forman JSON by GOlang?

I'm working with the Notion API and I can't use JSON correctly to send
My JSON:
{"parent":{"database_id":"123456"},"properties":{"Description":{"title":[{"text":{"content":"text1"}}]},"Value":{"rich_text":[{"text":{"content":"text2"}}]},"Status":{"rich_text":[{"text":{"content":"text4"
}}]},"Golang":{"rich_text":[{"text":{"content":"huinya"}}]},"Checkbox":{"Done?":true}}}
All correct Everything is correct except for the last paragraph.
"Checkbox":{"Done?":true}}}
Its must look like this :
{
"Done?": {
"checkbox": true
}
}
My data structure in Go big, and u can see it here go.dev
changind by place data structure
Add new type struct I put inside a map with string as key and bool as a value and in the tag add the json key that you want to have after marshalling
I hope this code can help you
type Done struct {
Done map[string]bool `json:"Done?"`
}
Js := Done{
Done: map[string]bool{
"checkbox": true,
},
}
b, err := json.Marshal(&Js)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(b))

Is it possible to Unmarshall a JSON which has varying field?

I am tring to get League of Legends champion informations from LOL static database. Link is given below.
Get info for specific hero
The problem is that i can only make request by hero names and all JSON responses are different from each other by only one field which is a "main" field; hero name. You can find problematic field as highlighted below:
Also tree respresentation:
My goal is to get all hero informations with iteration by range of known hero names as slice. You can check the code. I need only a couple of fields but the main tag is varies with every new request.
func GetHeroInfo(heroName string) *LolHeroInfo {
getUrl := fmt.Sprintf("http://ddragon.leagueoflegends.com/cdn/12.2.1/data/en_US/champion/%s.json", heroName)
fmt.Println(getUrl)
resp, err := http.Get(getUrl)
if err != nil {
fmt.Println(err)
return nil
}
defer resp.Body.Close()
read, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
return nil
}
heroGoverted := LolHeroInfo{}
err = json.Unmarshal(read, &heroGoverted)
if err != nil {
fmt.Println("unmarshall failed:", err)
return nil
}
return &heroGoverted }
Struct type LolHeroInfo is structifyed from this link: mholt's JSON to struct
You can check JSON response for another hero eg: JSON response for Annie .
Is there any way to make an agnostic struct field/tag for a JSON field. I believe this will be very hard because encoding/json package needs to check for field for particular tag in that JSON but maybe you encountered this kind of problem before. Creating separate struct for each hero is impossible so i will drop this case if i can't find a solution.
Thanks in advance for help.
Since you know it's just a single unknown key, you could just decode into a map[string]LolHeroInfo for the Data field, then do
heroGoverted := LolHeroInfo{}
for _, v := range decoded.Data {
heroGoverted = v
}
To solve problem, I used #dave 's solution.
I breake main struct into two separate struct. This way varying JSON field eliminated:
type LolHeroInfo struct {
Type string `json:"type"`
Format string `json:"format"`
Version string `json:"version"`
Data map[string]HeroInfoStruct `json:"data"`
}
heroInfo := lib.GetHeroInfo(lolHeroes[i])
for _, v := range heroInfo.Data { //unmarshalled to first struct
a := lib.HeroInfoStruct{} //data field; second struct
a = v
fmt.Println(a.Lore)// now i can reach to every field that i need
}

Print POST JSON data

I have an issue printing the JSON from the POST.
I use gorilla/mux for routing
r := mux.NewRouter()
r.HandleFunc("/test", Point).Methods("POST")
http.ListenAndServe(":80", r)`
and in Point function I have
func Point(w http.ResponseWriter, r *http.Request) {
var callback Decoder
json.NewDecoder(r.Body).Decode(&callback)
}
But I can use this method only when I know the structure and I want to figure out how to log.Print the whole JSON as a string. I tried
func Point(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
log.Println(r.Form)
}
But it prints an empty map. Please help to figure out this.
In the assumption that you are building a standard API endpoint which receives some JSON and you would like to do something with it you should approach it the following way.
Edit:
As mentioned in the comments when you use the ioutil.ReadAll()
function as in this example it will read everything that is sent in the
post request into the application memory. It's a good idea to check
this in a production application (e.g limiting payload size).
1.) Make a struct which will hold the data coming from an API post request in GoLang
2.) Convert your request body into a byte array []byte
3.) Unmarshal your []byte into a single instance of your struct made earlier.
I'll put an example below:
1. Make a struct which you'll put your JSON into.
Let's take an example of a simple blog post.
The JSON object looks like this and has a slug, a title, and description
{
"slug": "test-slug",
"title": "This is the title",
"body": "This is the body of the page"
}
So your struct would look like this:
type Page struct {
Slug string `json:"slug"`
Title string `json:"title"`
Body string `json:"body"`
}
2 - 3. Get the body of your request and convert it to byte[] Then take that string and Unmarshal it into an instance of your struct.
The data of a post request is the request 'Body'.
In Golang the request in almost all cases (unless you're using something fancy outside of the defaults) will be an http.Request object. This is the 'r' which you normally have in your normal code and it holds the 'Body' of our POST request.
import (
"encoding/json"
"github.com/go-chi/chi" // you can remove
"github.com/go-chi/render" // you can remove but be sure to remove where it is used as well below.
"io/ioutil"
"net/http"
)
func GiveMeAPage(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("A page"))
}
So what we are going to do here is convert an io.ReadCloser, which is what the http.Request.Body is, to a []byte as the Unmarshal function takes a []byte type. I've commented inline below for you.
func Create(w http.ResponseWriter, r *http.Request) {
var p Page //Create an instance of our struct
//Read all the data in r.Body from a byte[], convert it to a string, and assign store it in 's'.
s, err := ioutil.ReadAll(r.Body)
if err != nil {
panic(err) // This would normally be a normal Error http response but I've put this here so it's easy for you to test.
}
// use the built in Unmarshal function to put the string we got above into the empty page we created at the top. Notice the &p. The & is important, if you don't understand it go and do the 'Tour of Go' again.
err = json.Unmarshal(s, &p)
if err != nil {
panic(err) // This would normally be a normal Error http response but I've put this here so it's easy for you to test.
}
// From here you have a proper Page object which is filled. Do what you want with it.
render.JSON(w, r, p) // This is me using a useful helper function from go-chi which 'Marshals' a struct to a json string and returns it to using the http.ResponseWriter.
}
As a side note. Please don't use Decoder to parse JSON unless you are using JSON streams. You are not here, and it's unlikely you will
for a while. You can read about why that is
here
If you just want the raw JSON data without parsing it, http.Request.Body implements io.Reader, so you can just Read from it. For example with ioutil.ReadAll.
Something like (untested):
func Point(w http.ResponseWriter, r *http.Request) {
data, err := ioutil.ReadAll(r.Body)
// check error
// do whatever you want with the raw data (you can `json.Unmarshal` it too)
}

Editing Json in Go without Unmarshalling into Structs First

I am having a bit of an issue. So I am writing a tool in go that works with some json files.
The way the tool works is the devops member who is using it is supposed to upload their json file into the specified folder within the project and then that json file is used from there to deploy an api in api-gateway (the json is actually a swagger with extensions but that isn't particularly important to my question)
The issue I am having is I need to update ONE line in the json. Each file passed in will be different, but it is guaranteed to have a url in the same spot every time, just due to the nature of the project. I need to update this url in an automated fashion.
Due to the fact the json files are different, setting up hard coded structs and unmarshalling in order to edit is out of the question. The objective is for the devops members to not even have to go into the code, but rather just to deploy their files, which is the reason I was hoping for this to be automated.
So far my research has yielded nothing. It appears that Go only supports editing json if it is first unmarshaled into structs (see Modifying JSON file using Golang). Is there a way to edit without the structs if i know for a fact what I am looking for will always be available within the json, despite each file being different?
This is only my first month using go, so there may be a simple solution. I have seen some mention of scanners from the megajson library, but I cannot seem to get that to work either
{
"paths": {
"/account": {
"post": {
"something": "body",
"api": {
"uri": "http://thisiswhereineedtoedit.com"
}
}
}
}
}
Unmarshal to interface{}. Walk down nested objects to find the object with the value to set. Set the value. Marshal back to JSON.
var root interface{}
if err := json.Unmarshal(d, &root); err != nil {
log.Fatal(err)
}
// Walk down path to target object.
v := root
var path = []string{"paths", "/account", "post", "api"}
for i, k := range path {
m, ok := v.(map[string]interface{})
if !ok {
log.Fatalf("map not found at %s", strings.Join(path[:i+1], ", "))
}
v, ok = m[k]
if !ok {
log.Fatalf("value not found at %s", strings.Join(path[:i+1], ", "))
}
}
// Set value in the target object.
m, ok := v.(map[string]interface{})
if !ok {
log.Fatalf("map not found at %s", strings.Join(path, ", "))
}
m["uri"] = "the new URI"
// Marshal back to JSON. Variable d is []byte with the JSON
d, err := json.Marshal(root)
if err != nil {
log.Fatal(err)
}
Replace calls to log.Fatal with whatever error handling is appropriate for your application.
playground example
One way you can solve this is by reading the file and changing it.
Lets say you have the file as you mentioned:
example.json
{
"paths": {
"/account": {
"post": {
"something": "body",
"api": {
"uri": "http://thisiswhereineedtoedit.com"
}
}
}
}
}
And we want to change the line with "uri" in it.
You should be more specific then I was in this example, make a placeholder or something - to avoid changing the wrong line.
You can use a small program that would look something like this:
package main
import (
"io/ioutil"
"log"
"strings"
)
func main() {
file := "./example.json"
url := "\"uri\": \"supreme-uri\""
// Read the file
input, err := ioutil.ReadFile(file)
if err != nil {
log.Fatalln(err)
}
// Split it into lines
lines := strings.Split(string(input), "\n")
// Find the line that contains our "placeholder" / "uri"
for i, line := range lines {
if strings.Contains(line, "\"uri\":") {
// Replace the line
lines[i] = "\"uri\": " + url
}
}
// Join lines and write to file
output := strings.Join(lines, "\n")
err = ioutil.WriteFile(file, []byte(output), 0644)
if err != nil {
log.Fatalln(err)
}
}
And after running the program our example.json file now looks like this:
{
"paths": {
"/account": {
"post": {
"something": "body",
"api": {
"uri": "supreme-uri"
}
}
}
}
}
Hope you find this solution useful, Good luck! :]
You can try filepath pkg from cross-plane runtime. You specify the JSON path and get or set the result you want like the example in the above link.

XML into JSON Multiple Nesting

I'm attempting to write code to translate XML to JSON. The XML I'm trying to translate is as follows...
(Just a snippet)
`<version>0.1</version>
<termsofService>http://www.wunderground.com/weather/api/d/terms.html</termsofService>
<features>
<feature>conditions</feature>
</features>
<current_observation>
<image>
<url>http://icons.wxug.com/graphics/wu2/logo_130x80.png</url>
<title>Weather Underground</title>
<link>http://www.wunderground.com</link>
</image>
<display_location>
<full>Kearney, MO</full>
<city>Kearney</city>
<state>MO</state>
<state_name>Missouri</state_name>`
Current Code:
`package main
import (
"fmt"
"net/url"
"encoding/xml"
"net/http"
"log"
"io/ioutil"
"encoding/json"
)
type reportType struct{
Version xml.CharData `xml:"version"`
TermsOfService xml.CharData `xml:"termsofService"
`
Features xml.CharData `xml:"features>feature"`
Full xml.CharData `xml:"current_observation>display_location>full"`
StateName xml.CharData `xml:"current_observation>display_location>state_name"`
WindGust xml.CharData `xml:"current_observation>observation_location>full"`
Problem myErrorType `xml:"error"`
}
type myErrorType struct{
TypeOfError xml.CharData `xml:"type"`
Desciption xml.CharData `xml:"description"`
}
type reportTypeJson struct{
Version string `json:"version"`;
TermsOfService string `json:"termsofService"`;
Features map[string]string `json:"features"`;
Full map[string]string `json:"display_location"`;
WindGust map[string]string `json:"observation_location"`
}
func main() {
fmt.Println("data is from WeatherUnderground.")
fmt.Println("https://www.wunderground.com/")
var state, city string
str1 := "What is your state?"
str2 := "What is your city?"
fmt.Println(str1)
fmt.Scanf("%s", &state)
fmt.Println(str2)
fmt.Scanf("%s", &city)
baseURL := "http://api.wunderground.com/api/";
apiKey := "3hunna"
var query string
//set up the query
query = baseURL+apiKey +
"/conditions/q/"+
url.QueryEscape(state)+ "/"+
url.QueryEscape(city)+ ".xml"
fmt.Println("The escaped query: "+query)
response, err := http.Get(query)
doErr(err, "After the GET")
var body []byte
body, err = ioutil.ReadAll(response.Body)
doErr(err, "After Readall")
fmt.Println(body);
fmt.Printf("The body: %s\n",body)
//Unmarshalling
var report reportType
xml.Unmarshal(body, &report)
fmt.Printf("The Report: %s\n", report)
fmt.Printf("The description is [%s]\n",report.Problem.Desciption)
//Now marshal the data out in JSON
var data []byte
var output reportTypeJson
output.Version = string(report.Version);
output.TermsOfService = string(report.TermsOfService)
output.Features= map[string]string{"feature":string(report.Features)} // allocate a map, add the 'features' value to it and assign it to output.Features
output.Full=map[string]string{"full":string(report.Full),"state_name":string(report.StateName)}
output.WindGust=map[string]string{"full":string(report.WindGust)}
data,err = json.MarshalIndent(output,""," ")
doErr(err, "From marshalIndent")
fmt.Printf("JSON output nicely formatted: \n%s\n",data)
}
func doErr( err error, message string){
if err != nil{
log.Panicf("ERROR: %s %s \n", message, err.Error())
}
}
As you can see, I'm using maps to map one level nesting such as in the features case. But for in two level nesting cases such as xml:"current_observation>display_location>state_name", I can't figure out how to create the very first level, in this case current_observations. Would there be a way to somehow create a map of maps of sorts? Any and all ideas are much appreciated because I am very confused at the moment, Thanks for your time!
And the Output:
JSON output nicely formatted:
{
"version": "0.1",
"termsofService": "http://www.wunderground.com/weather/api/d/terms.html",
"features": {
"feature": "conditions"
},
"display_location": {
"full": "Kearney, MO",
"state_name": "Missouri"
},
"observation_location": {
"full": "Stonecrest, Kearney, Missouri"
}
}
You could use either structs or a map of maps. I'll give some examples of both, starting with the map of maps. The type would be declares as;
CurrentObservation map[string]map[string]string `json:"current_observation"`
In this case you have a map with strings as the keys and the value is another map that has string for both key and value. As a result when you marshal your json you will end up with something like;
"current_observation" {
"image": { // first level where the value is a map[string]string
"title":"Weather Underground" // inner map, string to string
}
}
If say you wanted to just print the title, you would do;
fmt.Println(reportJson.CurrentObservation["image"]["title"])
Since the data there looks fairly static you could also use structs instead. In which case you'd use something like this;
CurrentObservation CurrentObservation `json:"current_observation"`
type CurrentObservation struct {
Image Image `json:"image"`
}
type Image struct {
Url string `json:"url"`
Title string `json:"title"`
Link string `json:"link"`
}
Both options produce the same output though they could behave differently for different inputs. For example, if another version of current_observation were received as input that for example has another nested item in it call it... previous_observation then the map option would automatically unmarhsal this data as well where the struct options would exclude it since there would be no mapping to any object/type in Go.
Personally I prefer the struct route when possible but it varies from case to case. For your application the map is likely better since you're not working with the input (it comes in as xml) and you just want to print it, you don't really have to deal with the details of current_observation, if it has 3 objects inside it, they'll all be output as expected, if it were 5 it would be the same. With the structs you have to explicitly define every single field which isn't really necessary if you're just transforming the input. The advantage of the struct is more for use later on where you have type safety although in this case, I would say they're still fairly equivalent because for example anytime you want to access something in image, like CurrentObservation.Image.Title you'll have to perform a check to ensure Image is not nil, like;
if CurrentObservation.Image != nil {
fmt.Println(CurrentObservation.Image.Title)
}
With the map you basically have the same overhead, only you're checking for the existence of a key rather than checking if one of the inner structs is nil or not.
EDIT: example of initializing the map of maps using composite literal syntax;
reportJson.CurrentObservation := map[string]map[string]string {
"display_location": map[string]string {
"full": report.Full,
"state_name": report.StateName,
},
}