YAML — один из наиболее популярных форматов…
Они сами не знают — форматом чего, на самом деле.
Изначально он был «Yet Another Markup Language» — «Ещё один язык разметки», позже стал «YAML Ain’t Markup Language» — «YAML — не язык разметки» ((с) Wiki Rus и Wiki Eng):
Originally YAML was said to mean Yet Another Markup Language,[12] referencing its purpose as a markup languagewith the yet another construct, but it was then repurposed as YAML Ain’t Markup Language, a recursive acronym, to distinguish its purpose as data-oriented, rather than document markup.
В той Википедии даже слово «дружественный» взято в кавычки, с чем лично я совершенно солидарен.
Вообще — просто ещё один формат сериализации данных, наследник JSON с дополнительными возможностями.
В недавнем опросе в Ukrainian DevOps Community YAML vs JSON — YAML набрал процентов 90% голосов, так что в самом деле на данный момент является наиболее популярным.
Лично для меня JSON был и остаётся наиболее предпочтительным форматом, но YAML приходится использовать.
Собственно, в этом посте — краткий обзор его основных типов данных и сравнение форматирования с JSON.
Содержание
Основные принципы работы с YAML
- всегда используйте UTF-8 во избежание ошибок
- никогда не используйте TAB для отступов
Валидация YAML
Для проверки синтаксиса YAML в Linux можно использовать yamllint.
Устанавливаем:
[simterm]
$ sudo pacman -S yamllint
[/simterm]
Проверяем:
[simterm]
$ yamllint monitoring.yml monitoring.yml 1:1 warning missing document start "---" (document-start) 20:34 error trailing spaces (trailing-spaces) 22:32 error trailing spaces (trailing-spaces) 23:37 error trailing spaces (trailing-spaces) 33:7 error wrong indentation: expected 8 but found 6 (indentation) 35:9 error wrong indentation: expected 10 but found 8 (indentation) 36:11 error wrong indentation: expected 12 but found 10 (indentation)
[/simterm]
Правда при этом сам файл парсится Ansibl-ом нормально — но ошибки в форматировании есть.
Валидация JSON
И для примера — валидация JSON-документов из консоли Linux, используя модуль json:
[simterm]
$ python -m json.tool < json-example.json
{
"key1": "value1",
}
[/simterm]
vim плагин
Имеется плагин vim-yaml.
Добавляем в .vimrc:
...
" https://vimawesome.com/plugin/vim-yaml-all-too-well
Plug 'avakhov/vim-yaml'
" add yaml stuffs
au! BufNewFile,BufReadPost *.{yaml,yml} set filetype=yaml foldmethod=indent
autocmd FileType yaml setlocal ts=2 sts=2 sw=2 expandtab
...
Перечитываем конфиг, устанавливаем плагин:
[simterm]
:source % :PlugInstall
[/simterm]
PyYAML
Для работы с YAML в Python имеется библиотека PyYAML.
Примеры работы с ней — ниже.
Форматирование в YAML
Комментарии в YAML
Одно из немногих преимуществ — возможность добавления комментариев.
Формат комментирования стандартен — использется #.
Добавление комментария допускается в любом месте строки.
Примеры:
--- # I'm comment - name: somestring value1: "# I'm not a comment!" value: anotherstring # another comment
Отступы
Основная головная боль YAML — отступы.
При этом во всём файле количество пробелов (не табуляций — только пробелы) в начале строк должно быть одинаковым.
Т.е. если для разделения элементов в одном месте используются два пробела — то во всём файле должны использоваться только два пробела, и никак иначе.
Более того — принято использовать 2 пробела, хотя допустимо любое, главное — одинаковое везде и во всём.
Например:
---
parent_key:
key1: "value1"
key2: "value2"
key3: "%value3"
Будет являться валидным форматом, а:
---
parent_key1:
key1: "value1"
key2: "value2"
key3: "%value3"
parent_key2:
key1: "value1"
key2: "value2"
key3: "%value3"
Уже нет.
Тогда как в Python, который часто любят ругать за жёсткую привязку к пробелам — такое форматирование допустимо (хоть и будет нарушением стандарта):
#!/usr/bin/env python
def a():
print("A")
def b():
print("B")
a()
b()
И результат:
[simterm]
$ python spaces.py A B
[/simterm]
Однострочный YAML
Кроме стандартного вида и разделения пробелами — можно использовать запись в одну строку, аналогично JSON, например:
---
parent_key: {key1: "value1", key2: "value2"}
Literal Block Scalar
YAML поддерживает возможность записи многострочных строковых блочных скаляров и имеет три варианта их записи — обычный, с помощью разделителя «|» и «>«.
Обычный формат будет выглядеть так:
---
string: This
is
some text
without newlines
Результат в консоли Python:
[simterm]
>>> yaml.load(open('yaml-example.yml'))
{'string': 'This is some text without newlines'}
[/simterm]
При использовании символа | (Literal style) — в значении будут сохранены все символы новой строки и замыкающие пробелы:
---
string: |
This
is
some text
with newlines
Результат:
[simterm]
>>> yaml.load(open('yaml-example.yml'))
{'string': 'This\nis\nsome text\nwith newlines\n'}
[/simterm]
И с помощью > (Folded style):
---
string: >
This
is
some text
without newlines
Что вернёт весь текст одной строкой + замыкающий символ новой строки:
[simterm]
>>> yaml.load(open('yaml-example.yml'))
{'string': 'This is some text without newlines\n'}
[/simterm]
При этом — вам всё-равно придётся поддерживать равное кол-во пробелов перед каждой строкой в самом YAML-файле.
См. шикарный ответ на StackOverflow тут>>>:
There are 5 6 NINE (or 63*, depending how you count) different ways to write multi-line strings in YAML.
Базовые форматы данных в YAML
В YAML используются три основных формата:
- scalars: простейший типа ключ:значение
- списки или последовательности (list/sequence): упорядоченные по индексам данные
- словари (dictionary/mapping): схожи со скалярами, но могут иметь вложенные данные в т.ч. других типов
Scalars
Самый простой тип — скаляры, представляющие собой пару ключ:значение:
--- key1: "value1" key2: "value2"
Использование кавычек для строковых данных категорически рекомендуется во избежание проблем со специальными символами:
[simterm]
$ cat example.yml --- key1: "value1" key2: "value2" key3: %value3
[/simterm]
Проверяем:
[simterm]
$ yamllint example.yml example.yml 4:7 error syntax error: found character '%' that cannot start any token
[/simterm]
При этом значения типа true/false и integer можно смело указывать без кавычек.
Scalars — YAML vs JSON
Для сравнения — ключ:значение в YAML:
--- key: "value"
JSON:
{
"key": "value"
}
Python
Пример работы с YAML-скалярами в Python:
[simterm]
>>> import yaml
>>> yaml.load("""
... key: "value"
... """)
{'key': 'value'}
[/simterm]
Или из файла:
[simterm]
>>> import yaml
>>> yaml.load(open('yaml-example.yml'))
{'key': 'value'}
[/simterm]
Списки в YAML
Списки (последовательности, lists, sequences, collections) представляют собой коллекции упорядоченных данных, доступ к которым возможен по их индексам.
Пример списка:
# SIMPLE LIST - element1 - element2
Вложенные списки
Аналогично примерам выше — списки могут иметь вложенные списки, например:
# SIMPLE LIST - element1 - element2 # nested list - - element1
Именованные списки:
--- itemname: - valuename
При этом списки могут содержать скаляры или словари (про словари позже):
---
itemname:
- valuename
- scalar: "value"
- dict: {item1: "value1", item2: "value2"}
Lists — YAML vs JSON
Список в YAML:
--- - item1 - item2 - item3
Список в JSON:
[
"item1",
"item2",
"item3"
]
Вложенный список в YAML:
--- - item1 - item2 - item3 - - nested1
Вложенный список в JSON:
[
"item1",
"item2",
"item3",
[
"nested1"
]
]
Python и YAML-списки
Тут всё аналогично:
[simterm]
>>> yaml.load(open('yaml-example.yml'))
['item1', 'item2', 'item3', ['nested1']]
>>> for i in yaml.load(open('yaml-example.yml')):
... print(i)
...
item1
item2
item3
['nested1']
[/simterm]
Словари
Словари, они же dictionaries, они же mappings, схожи со калярами и содержат пары ключ:значение и, в отличии от скаляров, которые являются элементарным типом — могут содержать вложенные элементы:
--- key1: "value1" key2: - value2 - value3
Или вложенные словари:
---
key1: "value1"
key2:
- value2
- value3
key3:
key4: "value4"
key5: "value5"
key6:
key7: "value7"
Dictionary — JSON vs YAML
Словарь в YAML:
--- key1: "value1" key2: - value2 - value3
И он же в JSON:
{
"key1": "value1",
"key2": [
"value2",
"value3"
]
}
Python
[simterm]
>>> yaml.load(open('yaml-example.yml'))
{'key1': 'value1', 'key2': ['value2', 'value3']}
>>> type(yaml.load(open('yaml-example.yml')))
<class 'dict'>
[/simterm]
И, конечно, доступны все стандартные операции со словарями:
[simterm]
>>> dict = yaml.load(open('yaml-example.yml'))
>>> type(dict)
<class 'dict'>
>>> dict.update({'key3':'value3'})
>>> print(dict)
{'key1': 'value1', 'key2': ['value2', 'value3'], 'key3': 'value3'}
[/simterm]
В целом — на этом всё, хотя у YAML много других возможностей.
Смотрите: