diff --git a/ru/07.0.md b/ru/07.0.md new file mode 100644 index 000000000..9f671238f --- /dev/null +++ b/ru/07.0.md @@ -0,0 +1,12 @@ +# 7 Текстовые файлы + +Работа с текстовыми файлами — важная часть веб-разработки. Нам часто нужно создавать или обрабатывать полученный текстовый контент, включая строки, числа, JSON, XML и т. д. Как язык с высокой производительностью, Go имеет хорошую поддержку для этого в своей стандартной библиотеке. Вы обнаружите, что эти вспомогательные библиотеки просто потрясающие и позволят вам легко работать с любым текстовым контентом, с которым вы можете столкнуться. Эта глава состоит из 4 разделов и познакомит вас с обработкой текста в Go. + +XML — это интерактивный язык, который обычно используется во многих API, многие веб-серверы, написанные на Java, используют XML в качестве стандартного языка взаимодействия. Подробнее об XML мы поговорим в разделе 7.1. В разделе 7.2 мы рассмотрим JSON, который стал очень популярен в последние годы и намного удобнее, чем XML. В разделе 7.3 мы поговорим о регулярных выражениях, которые (для большинства людей) выглядят как язык, используемый пришельцами. В разделе 7.4 вы увидите, как шаблон MVC используется для разработки приложений в Go, а также как использовать пакет `template` для создания шаблонов ваших представлений. В разделе 7.5 мы познакомим вас с операциями с файлами и папками. Наконец, мы объясним некоторые операции со строками в Go в разделе 7.6. + + +## Ссылки + +- [Содержание](preface.md) +- Предыдущий раздел: [Итоги главы 6](06.5.md) +- Следующий раздел: [XML](07.1.md) \ No newline at end of file diff --git a/ru/07.1.md b/ru/07.1.md new file mode 100644 index 000000000..6e073976c --- /dev/null +++ b/ru/07.1.md @@ -0,0 +1,217 @@ +# 7.1 XML + +XML — широко используемый формат передачи данных в веб-сервисах. Сегодня он играет все более важную роль в веб-разработке. В этом разделе мы расскажем, как работать с XML через стандартную библиотеку Go. + +Я не буду пытаться обучать синтаксису или соглашениям XML. Для этого, пожалуйста, прочтите больше документации о самом XML. Мы сосредоточимся только на том, как кодировать и декодировать файлы XML в Go. + +Предположим, вы работаете в сфере ИТ, и вам приходится иметь дело со следующим файлом конфигурации XML: +```xml + + + + Shanghai_VPN + 127.0.0.1 + + + Beijing_VPN + 127.0.0.2 + + +``` +Приведенный выше XML-документ содержит два вида информации о вашем сервере: имя сервера и IP-адрес. Мы будем использовать этот документ в наших следующих примерах. + +## Разобор(парсинг) XML + +Как мы разбираем этот XML-документ? Для этого мы можем использовать функцию `Unmarshal` в пакете `xml` Go. + + func Unmarshal(data []byte, v interface{}) error + +параметр `data` получает поток данных из источника XML, а `v` – это структура, в которую вы хотите вывести проанализированный XML. Это интерфейс, который означает, что вы можете преобразовать XML в любую структуру, которую пожелаете. Здесь мы поговорим только о том, как преобразовать XML в тип `struct`, так как они имеют схожие древовидные структуры. + +Вот пример кода: +```Go +package main + +import ( + "encoding/xml" + "fmt" + "io/ioutil" + "os" +) + +type Recurlyservers struct { + XMLName xml.Name `xml:"servers"` + Version string `xml:"version,attr"` + Svs []server `xml:"server"` + Description string `xml:",innerxml"` +} + +type server struct { + XMLName xml.Name `xml:"server"` + ServerName string `xml:"serverName"` + ServerIP string `xml:"serverIP"` +} + +func main() { + file, err := os.Open("servers.xml") // For read access. + if err != nil { + fmt.Printf("error: %v", err) + return + } + defer file.Close() + data, err := ioutil.ReadAll(file) + if err != nil { + fmt.Printf("error: %v", err) + return + } + v := Recurlyservers{} + err = xml.Unmarshal(data, &v) + if err != nil { + fmt.Printf("error: %v", err) + return + } + + fmt.Println(v) +} +``` +XML на самом деле является древовидной структурой данных, и мы можем определить очень похожую структуру, используя структуры в Go, а затем использовать `xml.Unmarshal` для преобразования из XML в наш объект структуры. Пример кода напечатает следующее содержимое: + +```xml +{{ servers} 1 [{{ server} Shanghai_VPN 127.0.0.1} {{ server} Beijing_VPN 127.0.0.2}] + + Shanghai_VPN + 127.0.0.1 + + + Beijing_VPN + 127.0.0.2 + +} +``` +Мы используем `xml.Unmarshal` для анализа XML-документа на соответствующий объект структуры. Вы должны увидеть, что у нас есть что-то вроде `xml:"serverName"` в нашей структуре. Это функция структур, называемая тегами структур, помогающая с отражением. Давайте еще раз посмотрим на определение Unmarshal: + +```Go +func Unmarshal(data []byte, v interface{}) error +``` +Первый аргумент — это поток данных XML. Второй аргумент является типом хранения и поддерживает типы struct, slice и string. XML-пакет Go использует отражение для сопоставления данных, поэтому все поля в v должны быть экспортированы. Однако это вызывает проблему: как узнать, какое поле XML соответствует отображаемому полю структуры? Ответ заключается в том, что синтаксический анализатор XML анализирует данные в определенном порядке. Библиотека сначала попытается найти соответствующий тег структуры. Если совпадение найти не удается, выполняется поиск по именам полей структуры. Имейте в виду, что все теги, имена полей и XML-элементы чувствительны к регистру, поэтому вы должны убедиться, что существует однозначное соответствие для успешного сопоставления. + +Механизм отражения Go позволяет вам использовать эту информацию тега для отражения XML-данных в объекте структуры. Если вы хотите узнать больше об отражении в Go, прочтите документацию по пакету, посвященную тегам структур и отражению. + +Вот некоторые правила использования пакета xml для преобразования XML-документов в структуры: + +- Если тип поля является строкой или []byte с тегом `,innerxml`, `Unmarshal` назначит ему необработанные XML-данные, такие как `Description` в приведенном выше примере: + + + Shanghai_VPN127.0.0.1Beijing_VPN127.0.0.2 + +- Если поле называется `XMLName` и его тип `xml.Name`, тогда оно получает имя элемента, например `servers` в приведенном выше примере. +- Если тег поля содержит имя соответствующего элемента, то он также получает имя элемента, например `servername` и `serverip` в приведенном выше примере. +- Если тег поля содержит `,attr`, то он получает соответствующий атрибут элемента, например `vversion` в приведенном выше примере. +- Если тег поля содержит что-то вроде `"a>b>c"`, он получает значение элемента c узла b узла a. +- Если тег поля содержит `"="`, то он ничего не получает. - Если тег поля содержит `,any`, то он получает все дочерние элементы, которые не соответствуют другим правилам. +- Если XML-элементы имеют один или несколько комментариев, все эти комментарии будут добавлены к первому полю с тегом, содержащим `",comments"`. Этот тип поля может быть строкой или `[]byte`. Если такого поля не существует, все комментарии отбрасываются. + +Эти правила говорят вам, как определять теги в структурах. Как только вы поймете эти правила, сопоставление XML со структурами будет таким же простым, как приведенный выше пример кода. Поскольку теги и элементы XML имеют однозначное соответствие, мы также можем использовать срезы для представления нескольких элементов на одном уровне. + +Обратите внимание, что все поля в структурах должны быть экспортированы (с заглавными буквами), чтобы правильно анализировать данные. + +## Создание XML + +Что, если мы хотим создать XML-документ, а не анализировать его. Как это сделать в Go? Неудивительно, что пакет `xml` предоставляет две функции: `Marshal` и `MarshalIndent`, причем вторая функция автоматически устанавливает отступы в упорядоченном XML-документе. Их определение следующее: + +```Go +func Marshal(v interface{}) ([]byte, error) +func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) +``` +Первый аргумент в обеих этих функциях предназначен для хранения упорядоченного потока данных XML. + +Давайте посмотрим на пример, чтобы увидеть, как это работает: +```Go +package main + +import ( + "encoding/xml" + "fmt" + "os" +) + +type Servers struct { + XMLName xml.Name `xml:"servers"` + Version string `xml:"version,attr"` + Svs []server `xml:"server"` +} + +type server struct { + ServerName string `xml:"serverName"` + ServerIP string `xml:"serverIP"` +} + +func main() { + v := &Servers{Version: "1"} + v.Svs = append(v.Svs, server{"Shanghai_VPN", "127.0.0.1"}) + v.Svs = append(v.Svs, server{"Beijing_VPN", "127.0.0.2"}) + output, err := xml.MarshalIndent(v, " ", " ") + if err != nil { + fmt.Printf("error: %v\n", err) + } + os.Stdout.Write([]byte(xml.Header)) + + os.Stdout.Write(output) +} +``` +В приведенном выше примере выводится следующая информация: +```xml + + + + Shanghai_VPN + 127.0.0.1 + + + Beijing_VPN + 127.0.0.2 + + +``` +Как мы определили ранее, причина, по которой у нас есть `os.Stdout.Write([]byte(xml.Header))`, заключается в том, что и `xml.MarshalIndent`, и `xml.Marshal` не выводят заголовки XML сами по себе. , поэтому мы должны явно напечатать их, чтобы правильно создавать XML-документы. Здесь мы видим, что `Marshal` также получает параметр v типа `interface{}`. Итак, каковы правила маршалинга в XML-документе? + +- Если v является массивом или срезом, он печатает все элементы как значение. +- Если v является указателем, он печатает содержимое, на которое указывает v, и ничего не печатает, когда v равен нулю. +- Если v является интерфейсом, он также имеет дело с интерфейсом. +- Если v является одним из других типов, он печатает значение этого типа. + +Так как же `xml.Marshal` определяет имя элемента? Он следует следующим правилам: +- Если v является структурой, она определяет имя в теге XMLName. +- Имя поля — XMLName, а тип — xml.Name. +- Тег поля в структуре. +- Имя поля в структуре. +- Введите имя маршала. + + Затем нам нужно выяснить, как установить теги, чтобы создать окончательный XML-документ. + +- Имя XML не будет напечатано. +- Поля с тегами, содержащими `"-"`, не будут напечатаны. +- Если тег содержит `"name,attr"`, он использует имя в качестве имени атрибута и значение поля в качестве значения, например `версия` в приведенном выше примере. +- Если тег содержит `,attr`, он использует имя поля в качестве имени атрибута и значение поля в качестве его значения. +- Если тег содержит `,chardata`, он печатает символьные данные вместо элемента. +- Если тег содержит `,innerxml`, он печатает необработанное значение. +- Если тег содержит `,comment`, он печатается как комментарий без экранирования, поэтому в его значении не может быть "--". +- Если тег содержит `"omitempty"`, он опускает это поле, если его значение равно нулю, включая false, 0, nil-указатель или nil-интерфейс, нулевую длину массива, среза, карты и строки. +- Если тег содержит `"a>b>c"`, он печатает три элемента, где a содержит b, а b содержит c, как в следующем коде: + +```xml +FirstName string `xml:"name>first"` +LastName string `xml:"name>last"` + + +Asta +Xie + +``` +Вы могли заметить, что структурные теги очень полезны для работы с XML, и то же самое касается других форматов данных, которые мы будем обсуждать в следующих разделах. Если вы по-прежнему сталкиваетесь с проблемами при работе со структурными тегами, вам, вероятно, следует прочитать дополнительную документацию по ним, прежде чем переходить к следующему разделу. + +## Ссылки + +- [Содержание](preface.md) +- Предыдущий раздел: [Текстовые файлы](07.0.md) +- Следующий раздел: [JSON](07.2.md) diff --git a/ru/preface.md b/ru/preface.md index bd7b2fcf0..230b8423e 100644 --- a/ru/preface.md +++ b/ru/preface.md @@ -40,7 +40,7 @@ - 6.3. [Session storage](06.3.md) - 6.4. [Prevent hijack of session](06.4.md) - 6.5. [Итоги раздела](06.5.md) -- 7.[Text files](07.0.md) +- 7.[Текстовые файлы](07.0.md) - 7.1. [XML](07.1.md) - 7.2. [JSON](07.2.md) - 7.3. [Regexp](07.3.md)