Быстрый старт с Go: сканер погоды

Осваиваем импорт и преобразование XML-данных для собственных задач 
3 минуты8207

Продолжаем знакомиться с языком Go. В этот раз напишем программу, способную читать в интернете данные о погоде, — своего рода сканер погоды. Предварительно рекомендую прочитать статью «Быстрый старт с Go: первые шаги» — для нашей сегодняшней задачи вам потребуется знать основы языка, а также скачать и установить компилятор Go.

План работы над нашим сканером таков:

  • используем сайт, который выдаёт прогноз погоды в формате XML,
  • прочитаем оттуда данные по погоде средствами Go,
  • преобразуем их в удобный для обработки формат,
  • выберем то, что нам необходимо.

Настраиваем источник информации

Мы воспользуемся сайтом «Метеосервис», который позволяет получать информацию о погоде в выбранной стране и указанном городе. Чтобы получить нужную ссылку, переходим на страницу настройки сервиса. Выберем из списков страну и город — например, Россию и Москву. В результате чуть ниже, после слов «Местоположение сервиса», видим ссылку: https://xml.meteoservice.ru/export/gismeteo/point/32277.xml. Этот адрес возвращает в XML-формате информацию о погоде в выбранном городе. Его можно даже просто открыть в браузере. Ещё на странице настройки сервиса есть описание структуры получаемых данных.

Читаем данные с сайта

Для чтения данных по полученной ссылке используем GET-запрос по протоколу HTTP. Для отправки запросов в Go в пакете net/http определено несколько функций, по одной на каждый вид запроса. Нам нужна функция Get().

В качестве параметра она принимает адрес ресурса, к которому надо выполнить запрос, и возвращает объект http.Response, содержащий ответ сервера. Как и все функции, связанные с вводом-выводом, Get() вернёт ошибку, если она возникнет. 

Фрагмент кода с использованием Get() и обработкой ошибок будет выглядеть так:

response, err := http.Get("https://xml.meteoservice.ru/export/gismeteo/point/32277.xml")
if err != nil {
    log.Fatal(err)
}
defer response.Body.Close()

Последняя строка фрагмента содержит команду отложенного закрытия потока Body. Не забываем при этом импортировать соответствующие пакеты:

import (
    "net/http"
    "log"
)

Поле Body структуры http.Response представляет собой ответ от веб-ресурса и при этом является интерфейсом io.ReadCloser. Фактически это поле — поток для чтения, и его можно прочесть как массив байт, используя функцию ReadAll() пакета io/ioutil. Применим для этого следующий код, не забыв импортировать соответствующий пакет:

byteValue, err := ioutil.ReadAll(response.Body)
if err != nil {
    log.Fatal(err)
}

Результат можно легко вывести, к примеру, в консоль, преобразовав массив байт в строку:

fmt.Print(string(byteValue))

Формат данных XML и структуры

XML (eXtensible Markup Language) — это расширяемый язык разметки. В отличие от языка гипертекстовой разметки HTML, который содержит ограниченный набор тегов, XML позволяет разработчику использовать собственные теги.

В пакет библиотеки Go encoding/xml входят функции, позволяющие работать с XML. Нам потребуется функция xml.Unmarshall, преобразующая XML-данные в соответствующую структуру.

Структуры в Go — это специальный тип данных, определяемый разработчиком и служащий для описания какого-либо объекта. Структуры содержат набор полей, которые представляют различные атрибуты объекта. Для определения структуры применяются ключевые слова type и struct. Каждое поле имеет имя и тип, как переменная.

type person struct {
    name string
    age int
}

Предложенная выше структура, к примеру, описывает человека. Её имя — person. Она содержит два поля: name (имя человека, представляет тип string) и age (возраст человека, представляет тип int).

Распаковываем XML в структуру

Полученные с сайта XML-данные необходимо распаковать в структуру, имеющую поля, соответствующие тегам в наших данных. Создадим её с помощью онлайн-инструмента. Вводим адрес, по которому читаем XML, в строку — и нажимаем кнопку Get from URL. Или копируем полученный XML в левое окно. При этом в правом окне генерируется соответствующая структура на Go. Копируем её в свой код. Рекомендую внимательно изучить её поля и увидеть их соответствие XML-данным.

Затем объявляем переменную, типом которой будет наша структура. В эту переменную распаковываем полученные из интернета данные в формате XML, используя функцию xml.Unmarshal().

var weather MMWEATHER
err = xml.Unmarshal(byteValue, &weather)
if err != nil {
    log.Fatal(err)
}

Выбираем информацию из структуры

После распаковки переменная weather содержит в виде структуры данные, которые мы получили в формате XML. Для обращения к полям структуры используется точка. К примеру, чтобы вывести значения поля Sname, которое содержит название города, нужно написать:

fmt.Println(url.PathUnescape(weather.REPORT.TOWN.Sname))

То есть обратиться к полю Sname структуры TOWN, которая является полем структуры REPORT, выступающей в свою очередь полем переменной weather. Кроме того, нужно использовать функцию url.PathUnescape(), чтобы раскодировать значение этого поля. И не забыть при этом импортировать пакет net/url.

А если, к примеру, мы хотим получить все значения прогнозируемой максимальной температуры, достаточно использовать следующий фрагмент кода:

forecast := weather.REPORT.TOWN.FORECAST
for i := 0; i < len(forecast); i++ {
    fmt.Println("T.Max:", forecast[i].TEMPERATURE.Max)
}

Если нужно уточнить дату и время прогноза, достаточно добавить следующую строку в тело цикла:

fmt.Printf("Day: %s/%s %s:00\n", forecast[i].Day, forecast[i].Month, forecast[i].Hour)

Исследуя полученные XML и структуры, мы видим, что данные содержат также информацию о давлении, направлении, силе ветра и так далее. Чтобы поупражняться, можно попробовать вывести в консоль и эту информацию.

Заключение

Если у вас всё получилось — поздравляю! Если нет и возникли вопросы — пишите, спрашивайте, не стесняйтесь. Меня можно найти в Telegram под ником @biblelamp или на сайте GeekBrains. Желаю всем удачи и рекомендую никогда не останавливаться в изучении программирования.

Дополнительные материалы по Go для начинающих:

Первая часть цикла о Go-разработке:

Хотите получить системную подготовку? На факультете Go-разработки GeekUniversity вы за полтора года приобретёте все знания, необходимые для начала карьеры Go-разработчика, создадите собственное портфолио из нескольких работ и получите работу по специальности.

программированиеgolang
Нашли ошибку в тексте? Напишите нам.
Спасибо,
что читаете наш блог!