Server-Side Scripting/Internet Data/Go
routes/lesson8.go
edit// This program reads JSON data from Wikidata with countries
// and Celsius temperatures. It displays the data in Celsius
// and Fahrenheit sorted in decending order by temperature.
//
// File format:
// Country,MaximumTemperature
// Bulgaria,45.2 °C
// Canada,45 °C
//
// References:
// https://www.mathsisfun.com/temperature-conversion.html
// https://golang.org/doc/
// https://blog.alexellis.io/golang-json-api-client/
// https://www.sohamkamani.com/golang/json/
package routes
import (
"encoding/json"
"html/template"
"io/ioutil"
"log"
"net/http"
"path/filepath"
"sort"
"strconv"
"strings"
"time"
)
type Temperature8 struct {
country string
celsius float64
fahrenheit float64
}
func Lesson8(response http.ResponseWriter, request *http.Request) {
response.Header().Set("Content-Type", "text/html; charset=utf-8")
type Data struct {
Table template.HTML
}
result := ""
switch request.Method {
case "GET":
result = getData8()
default:
result = "Unexpected request method: " + request.Method
}
data := Data{template.HTML(result)}
path := filepath.Join("templates", "lesson8.html")
parsed, _ := template.ParseFiles(path)
parsed.Execute(response, data)
}
func getData8() string {
url := "https://query.wikidata.org/sparql"
query := `
SELECT DISTINCT ?Country ?MaximumTemperature WHERE {
?countryItem wdt:P31 wd:Q6256;
p:P6591 ?maximumTemperatureRecord.
?maximumTemperatureRecord psv:P6591 ?maximumTemperatureValue.
?maximumTemperatureValue wikibase:quantityAmount ?maximumTemperatureQuantity;
wikibase:quantityUnit ?temperatureUnit.
{
?countryItem rdfs:label ?Country.
FILTER((LANG(?Country)) = "en")
}
{
?temperatureUnit wdt:P5061 ?unitSymbol.
FILTER((LANG(?unitSymbol)) = "en")
FILTER(CONTAINS(?unitSymbol, "C"))
}
BIND(CONCAT(STR(?maximumTemperatureQuantity), " ", ?unitSymbol) AS ?MaximumTemperature)
}
ORDER BY (?Country)
`
body := getJson8(url, query)
temperatures := getTemperatures(body)
sort.Slice(temperatures, func(a, b int) bool {
return temperatures[a].celsius > temperatures[b].celsius
})
table := formatTable8(temperatures)
return table
}
func getJson8(url string, query string) []byte {
client := http.Client{Timeout: time.Second * 2}
request, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
log.Fatal(err)
}
requestQuery := request.URL.Query()
requestQuery.Add("query", query)
requestQuery.Add("format", "json")
request.URL.RawQuery = requestQuery.Encode()
response, err := client.Do(request)
if err != nil {
log.Fatal(err)
}
if response.Body != nil {
defer response.Body.Close()
}
body, err := ioutil.ReadAll(response.Body)
if err != nil {
log.Fatal(err)
}
return body
}
func getTemperatures(body []byte) []Temperature8 {
type Head struct {
Vars []string `json:"vars"`
}
type Country struct {
Value string `json:"Value"`
}
type MaximumTemperature struct {
Value string `json:"Value"`
}
type Bindings struct {
Country Country `json:"Country"`
Temperature MaximumTemperature `json:"MaximumTemperature"`
}
type Results struct {
Bindings []Bindings `json:"bindings"`
}
type Result struct {
Head Head `json:"head"`
Results Results `json:"results"`
}
var result Result
json.Unmarshal([]byte(body), &result)
var temperatures []Temperature8
for _, binding := range result.Results.Bindings {
country := binding.Country.Value
index := strings.Index(binding.Temperature.Value, " °C")
celsius, _ := strconv.ParseFloat(binding.Temperature.Value[0:index], 64)
fahrenheit := celsius * 9 / 5 + 32
temperature := Temperature8 {
country: country,
celsius: celsius,
fahrenheit: fahrenheit}
temperatures = append(temperatures, temperature)
}
return temperatures
}
func formatTable8(temperatures []Temperature8) string {
result := "<table><tr><th>Country</th>"
result += "<th>Celsius</th><th>Fahrenheit</th></tr>"
for _, temperature := range temperatures {
result += "<tr><td>" + temperature.country + "</td>"
result += "<td>" + strconv.FormatFloat(temperature.celsius, 'f', 1, 64) + "° C</td>"
result += "<td>" + strconv.FormatFloat(temperature.fahrenheit, 'f', 1, 64) + "° F</td></tr>"
}
result += "</table>"
return result
}
templates/lesson8.html
edit<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Lesson 8</title>
<link rel="stylesheet" href="styles.css">
<style>
p {
min-height: 1em;
}
</style>
</head>
<body>
<h1>Temperature Conversion</h1>
<h2>Wikidata</h2>
{{.Table}}
</body>
</html>
Try It
editSee Server-Side Scripting/Routes and Templates/Go to create a test environment.