Skip to content

07.0, 07.1 RU #1204

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions ru/07.0.md
Original file line number Diff line number Diff line change
@@ -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)
217 changes: 217 additions & 0 deletions ru/07.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
# 7.1 XML

XML — широко используемый формат передачи данных в веб-сервисах. Сегодня он играет все более важную роль в веб-разработке. В этом разделе мы расскажем, как работать с XML через стандартную библиотеку Go.

Я не буду пытаться обучать синтаксису или соглашениям XML. Для этого, пожалуйста, прочтите больше документации о самом XML. Мы сосредоточимся только на том, как кодировать и декодировать файлы XML в Go.

Предположим, вы работаете в сфере ИТ, и вам приходится иметь дело со следующим файлом конфигурации XML:
```xml
<?xml version="1.0" encoding="utf-8"?>
<servers version="1">
<server>
<serverName>Shanghai_VPN</serverName>
<serverIP>127.0.0.1</serverIP>
</server>
<server>
<serverName>Beijing_VPN</serverName>
<serverIP>127.0.0.2</serverIP>
</server>
</servers>
```
Приведенный выше 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}]
<server>
<serverName>Shanghai_VPN</serverName>
<serverIP>127.0.0.1</serverIP>
</server>
<server>
<serverName>Beijing_VPN</serverName>
<serverIP>127.0.0.2</serverIP>
</server>
}
```
Мы используем `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
<?xml version="1.0" encoding="UTF-8"?>
<servers version="1">
<server>
<serverName>Shanghai_VPN</serverName>
<serverIP>127.0.0.1</serverIP>
</server>
<server>
<serverName>Beijing_VPN</serverName>
<serverIP>127.0.0.2</serverIP>
</server>
</servers>
```
Как мы определили ранее, причина, по которой у нас есть `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"`

<name>
<first>Asta</first>
<last>Xie</last>
</name>
```
Вы могли заметить, что структурные теги очень полезны для работы с XML, и то же самое касается других форматов данных, которые мы будем обсуждать в следующих разделах. Если вы по-прежнему сталкиваетесь с проблемами при работе со структурными тегами, вам, вероятно, следует прочитать дополнительную документацию по ним, прежде чем переходить к следующему разделу.

## Ссылки

- [Содержание](preface.md)
- Предыдущий раздел: [Текстовые файлы](07.0.md)
- Следующий раздел: [JSON](07.2.md)
2 changes: 1 addition & 1 deletion ru/preface.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down