Welcome to part 15 of the Go programming tutorial series, where we'll be incorporating a map into our sitemap that we've pulled.
One issue we're going to come across immediately is when we find ourselves wanting to store 2 or more values in the map's value, because we can only specify one type. Have we any idea for how to create a type that contains multiple values? Sure we do! Structs! So, let's make our NewsMap struct:
type NewsMap struct {
Keyword string
Location string
}
In this case, our values inside are just 2 strings, but we could have chosen many types, even more custom types!
Now, our code up to this point:
package main
import (
"encoding/xml"
"fmt"
"io/ioutil"
"net/http"
)
type Sitemapindex struct {
Locations []string `xml:"sitemap>loc"`
}
type News struct {
Titles []string `xml:"url>news>title"`
Keywords []string `xml:"url>news>keywords"`
Locations []string `xml:"url>loc"`
}
type NewsMap struct {
Keyword string
Location string
}
func main() {
var s Sitemapindex
var n News
resp, _ := http.Get("https://www.washingtonpost.com/news-sitemap-index.xml")
bytes, _ := ioutil.ReadAll(resp.Body)
xml.Unmarshal(bytes, &s)
for _, Location := range s.Locations {
resp, _ := http.Get(Location)
bytes, _ := ioutil.ReadAll(resp.Body)
xml.Unmarshal(bytes, &n)
}
}
What we'd like to do now is iterate through n, and store our values into a map of the NewsMap type. First, before we iterate over the sitemap locations, let's add:
news_map := make(map[string]NewsMap)
So we have:
func main() {
var s Sitemapindex
var n News
resp, _ := http.Get("https://www.washingtonpost.com/news-sitemap-index.xml")
bytes, _ := ioutil.ReadAll(resp.Body)
xml.Unmarshal(bytes, &s)
news_map := make(map[string]NewsMap)
for _, Location := range s.Locations { ...
Next, after we've unmarshaled our data into our n, News type, we can populate our map with:
for idx, _ := range n.Keywords {
news_map[n.Titles[idx]] = NewsMap{n.Keywords[idx], n.Locations[idx]}
}
Then, our full main function will look like:
func main() {
var s Sitemapindex
var n News
resp, _ := http.Get("https://www.washingtonpost.com/news-sitemap-index.xml")
bytes, _ := ioutil.ReadAll(resp.Body)
xml.Unmarshal(bytes, &s)
news_map := make(map[string]NewsMap)
for _, Location := range s.Locations {
resp, _ := http.Get(Location)
bytes, _ := ioutil.ReadAll(resp.Body)
xml.Unmarshal(bytes, &n)
for idx, _ := range n.Keywords {
news_map[n.Titles[idx]] = NewsMap{n.Keywords[idx], n.Locations[idx]}
}
}
}
Next, what if we wanted to iterate over our map? We can do:
for idx, data := range news_map {
fmt.Println("\n\n\n",idx)
fmt.Println("\n",data.Keyword)
fmt.Println("\n",data.Location)
}
Full code up to this point:
package main
import (
"encoding/xml"
"fmt"
"io/ioutil"
"net/http"
)
type Sitemapindex struct {
Locations []string `xml:"sitemap>loc"`
}
type News struct {
Titles []string `xml:"url>news>title"`
Keywords []string `xml:"url>news>keywords"`
Locations []string `xml:"url>loc"`
}
type NewsMap struct {
Keyword string
Location string
}
func main() {
var s Sitemapindex
var n News
resp, _ := http.Get("https://www.washingtonpost.com/news-sitemap-index.xml")
bytes, _ := ioutil.ReadAll(resp.Body)
xml.Unmarshal(bytes, &s)
news_map := make(map[string]NewsMap)
for _, Location := range s.Locations {
resp, _ := http.Get(Location)
bytes, _ := ioutil.ReadAll(resp.Body)
xml.Unmarshal(bytes, &n)
for idx, _ := range n.Keywords {
news_map[n.Titles[idx]] = NewsMap{n.Keywords[idx], n.Locations[idx]}
}
}
for idx, data := range news_map {
fmt.Println("\n\n\n\n\n",idx)
fmt.Println("\n",data.Keyword)
fmt.Println("\n",data.Location)
}
}
Now, we've got the data we're interested in, and formatted in such a way that we could iterate through it. Next, we'll be back working with our web app.