А.3 Данные и форматы: JSON, XML, CSV, типы данных
Зачем это аналитику
Половина дефектов в интеграциях — не в логике, а в данных: дата в другом формате, сумма строкой, пропущенное поле, другая кодировка, другой часовой пояс. Аналитик, который точно описывает формат каждого поля, снимает эти дефекты ещё на этапе постановки.
Готовность к модулю
Модуль опирается на темы ниже. Если какая-то из них незнакома или её вопросы для самопроверки даются с трудом, начните с неё.
Куда ведёт
Тема подробнее раскрывается в модулях:
- А.4 Реляционные БД
- А.6 API и интеграции
- Б.3 Контракты API
- 5.1 Как работают LLM
- 8.4 Пакетные интеграции
- 8.6 Легаси, SOAP и шины
Что понять
- JSON: объект, массив, строка, число, логическое значение, null. Вложенные структуры и как ими описывать документы вроде заказа.
- XML: элементы, атрибуты, пространства имён — на уровне чтения. Где он ещё встречается (банки, госинтеграции, SOAP).
- CSV и файловый обмен: разделители, экранирование, заголовок, кодировка, проблема Excel с числами и датами.
- YAML как формат конфигураций: отступы и типичные ошибки.
- Типы данных и их ловушки: целые и дробные числа, деньги (почему не float), строки и их длина, логические значения.
- Даты и время: ISO 8601, часовые пояса, UTC, разница между датой и моментом времени.
- Кодировки: UTF-8 и почему появляются «кракозябры».
- Обязательность, null и пустое значение: три разных состояния поля.
- Схема данных: зачем описывать формат формально (JSON Schema, XSD) — первое знакомство.
Урок
В модуле А.2 у HTTP-запроса было тело, а заголовок Content-Type сообщал, в каком оно формате. Этот урок — о том, что внутри и где там прячутся ошибки. Две системы могут одинаково понимать бизнес-процесс и всё равно не договориться, потому что одна пишет дату как 03.04.2026, а другая читает её как 4 марта.
Сквозной пример — заказ интернет-магазина: покупатель, позиции, скидка, итог, дата оформления.
JSON
JSON (JavaScript Object Notation) — самый распространённый формат обмена данными между системами. Несмотря на название, он не привязан к языку JavaScript. Значение в JSON может быть одного из шести типов:
- объект — набор пар «ключ: значение» в фигурных скобках; ключ всегда строка в двойных кавычках;
- массив — упорядоченный список значений в квадратных скобках;
- строка — текст в двойных кавычках;
- число — целое или дробное, без кавычек, дробная часть через точку;
- логическое значение —
trueилиfalse; - null — явное «значения нет».
Объекты и массивы можно вкладывать друг в друга на любую глубину. Так описывают документы: заказ — объект, внутри него объект «покупатель» и массив позиций, каждая позиция — снова объект.
{
"orderId": 58213,
"createdAt": "2026-03-14T19:02:11+03:00",
"status": "NEW",
"customer": {
"customerId": 1042,
"fullName": "Иванова Анна",
"phone": "+79001234567"
},
"items": [
{ "productId": 77, "sku": "00457", "quantity": 2, "price": "1990.00" },
{ "productId": 81, "sku": "01120", "quantity": 1, "price": "450.00" }
],
"discount": "200.00",
"total": "4230.00",
"promoCode": null,
"isGift": false
}
Заметьте несколько решений в этом примере. Телефон и артикул — строки, хотя состоят из цифр: с ними не выполняют арифметику, а ведущий ноль или знак «+» важны. Суммы — тоже строки; почему, разберём ниже. Дата — строка в определённом формате, потому что отдельного типа «дата» в JSON нет.
У JSON нет комментариев и нет встроенного способа сказать, какие поля обязательны. Это решается схемой данных — о ней в конце урока.
XML
XML (eXtensible Markup Language) — более старый и многословный формат. Данные в нём размечаются тегами, как в HTML. Тот же фрагмент заказа:
<?xml version="1.0" encoding="UTF-8"?>
<order xmlns="urn:shop.example:orders:v1" id="58213" status="NEW">
<createdAt>2026-03-14T19:02:11+03:00</createdAt>
<customer id="1042">
<fullName>Иванова Анна</fullName>
</customer>
<items>
<item productId="77" quantity="2">
<price currency="RUB">1990.00</price>
</item>
</items>
<total currency="RUB">4230.00</total>
</order>
Три понятия, которых достаточно для чтения:
- Элемент — открывающий и закрывающий тег с содержимым:
<fullName>Иванова Анна</fullName>. Элементы вкладываются друг в друга и могут повторяться, как<item>внутри<items>. - Атрибут — пара «имя=”значение”» внутри открывающего тега:
id="58213",currency="RUB". Одни и те же данные можно положить и в атрибут, и в элемент; выбор — соглашение конкретной схемы. - Пространство имён (namespace) — атрибут
xmlnsс уникальным идентификатором. Он нужен, когда в одном документе встречаются элементы из разных словарей: например,<status>заказа и<status>платежа. Пространство имён говорит, чей этоstatus. Идентификатор выглядит как адрес, но обычно никуда не ведёт, это просто уникальное имя.
В XML все значения — текст, типов в самом документе нет. Что quantity целое число, а createdAt — дата, описывает отдельная схема (XSD).
Где XML встречается сегодня: банковские форматы и обмен с банками, государственные информационные системы и электронный документооборот, интеграции по протоколу SOAP, старые корпоративные шины и учётные системы. Новые публичные API чаще используют JSON.
CSV и файловый обмен
CSV (comma-separated values) — таблица в текстовом файле: одна строка файла — одна запись, значения разделены разделителем. Этим форматом обмениваются выгрузками остатков, прайс-листами, реестрами платежей.
sku;name;quantity;price
00457;"Чехол ""Классик"", чёрный";15;1990.00
01120;Защитное стекло;40;450.00
Формат кажется простым, но у него почти нет единого стандарта на практике, и каждое из следующих свойств надо оговаривать явно.
- Разделитель. Название обещает запятую, но в русскоязычной среде часто используют точку с запятой, потому что запятая — десятичный разделитель в числах. Встречается и табуляция.
- Экранирование. Если значение содержит разделитель, перевод строки или кавычку, его берут в двойные кавычки, а кавычку внутри удваивают, как во второй строке примера. Система, которая этого не делает, получит «лишние» столбцы в строке.
- Заголовок. Есть ли первая строка с названиями столбцов и важен ли порядок столбцов.
- Кодировка. UTF-8 или устаревшая однобайтовая (например, Windows-1251). Об этом подробнее ниже.
- Формат чисел и дат. Точка или запятая в дробях,
2026-03-14или14.03.2026.
Отдельная беда — Excel. Когда пользователь открывает CSV двойным щелчком, Excel сам угадывает типы и портит данные: артикул 00457 превращается в число 457, номер телефона или карты лояльности из 16+ цифр — в запись вида 1,23457E+15 с потерей последних цифр (Excel хранит не больше 15 значащих цифр), строка 03-04 — в дату. Если файл затем сохранить, испорченные значения уйдут в следующую систему.
Правила, которые стоит закладывать в требования к файловому обмену: явно указанные кодировка, разделитель и формат дат и чисел; обязательная строка заголовка; экранирование по общепринятым правилам; коды и артикулы — только как текст; запрет редактировать файлы обмена в Excel или отдельная инструкция по импорту с указанием типов столбцов. Подробнее пакетные интеграции разбираются в модуле 8.4.
YAML
YAML — формат, который чаще всего встречается не в обмене данными, а в конфигурациях: настройки приложений, описания развёртывания, спецификации API в формате OpenAPI. Структура в нём задаётся отступами, а не скобками.
service: order-service
payment:
url: https://pay.example/api
timeoutSeconds: 10
features:
freeDelivery: true
freeDeliveryThreshold: "3000.00"
regions:
- msk
- spb
Типичные ошибки:
- Отступы. Уровень вложенности определяется числом пробелов. Лишний пробел переносит настройку в другой раздел, и файл остаётся синтаксически правильным, но значит другое. Табуляция вместо пробелов запрещена.
- Угадывание типов. Значения без кавычек YAML пытается распознать сам.
1.10станет числом 1.1, а номер версии потеряет ноль. Строка012345может потерять ведущий ноль или, в некоторых библиотеках, прочитаться как восьмеричное число (в системе счисления по основанию 8:012345станет 5349). В библиотеках, следующих старой версии спецификации,no,yes,on,offчитаются как логические значения, и код страны Норвегииnoпревращается вfalse. Защита — брать в кавычки всё, что должно остаться строкой.
Типы данных и их ловушки
Формат задаёт синтаксис, а типы — смысл значений. Именно на типах чаще всего ломаются интеграции.
Целые числа. Идентификаторы, количества, счётчики. Ловушка — предел. У каждого целого типа в базе или языке есть максимум; счётчик, рассчитанный на миллионы, однажды переполнится. Вторая ловушка: в JavaScript и в ряде библиотек JSON числа хранятся как дробные с плавающей точкой, и целые больше 2^53 (около 9 · 10^15) теряют точность. Поэтому длинные идентификаторы в JSON часто передают строкой.
Дробные числа с плавающей точкой (float, double). Компьютер хранит их в двоичном виде, и большинство десятичных дробей представимы только приближённо. Классический пример: 0.1 + 0.2 в большинстве языков даёт 0.30000000000000004. Для физических измерений это допустимо, для денег — нет.
Деньги. Сумма должна складываться до копейки, иначе итог заказа разойдётся с суммой позиций, а сверка с банком — с выпиской. Поэтому деньги передают одним из двух способов:
- десятичной строкой с фиксированным числом знаков:
"4230.00", а на стороне системы хранят в точном десятичном типе (decimal, numeric); - целым числом в минимальных единицах валюты:
423000копеек.
К сумме почти всегда нужна валюта — отдельным полем или однозначным соглашением. И нужно правило округления: при расчёте скидки 7% от 1990.00 получается 139.30, но от 1995.00 — 139.65, а от 1999.99 — 139.9993, и кто-то должен решить, как это округлять.
Строки. Главный вопрос — длина. Её надо указывать в требованиях, и указывать, в чём она измеряется. В UTF-8 (кодировка — способ записать символы байтами, подробнее ниже; байт — минимальная ячейка памяти) латинская буква занимает один байт, кириллическая — два, некоторые символы — больше. Поле «до 50 символов» и поле «до 50 байт» для фамилии на кириллице различаются вдвое. Если одна система режет по символам, а другая по байтам, длинные русские названия товаров будут обрезаться или отклоняться.
Логические значения. В JSON это true и false, но на практике встречаются "Y"/"N", 1/0, "да"/"нет". Формат должен быть оговорён явно. И стоит проверить, что признак действительно двузначный: «оплачен / не оплачен» со временем часто обрастает частичным возвратом, и тогда нужен статус.
Даты и время
Для дат есть общепринятый стандарт — ISO 8601. Его основные формы:
| Что передаём | Пример | Смысл |
|---|---|---|
| Дата | 2026-03-14 |
Календарный день без времени |
| Момент в UTC | 2026-03-14T16:02:11Z |
Точка на шкале времени; Z означает UTC |
| Момент со смещением | 2026-03-14T19:02:11+03:00 |
Та же точка, записанная по местному времени со смещением от UTC |
| Время без зоны | 2026-03-14T19:02:11 |
Неоднозначно: неизвестно, в каком часовом поясе |
Вторая и третья строки таблицы описывают один и тот же момент. Четвёртая — источник ошибок: получатель подставит свой часовой пояс, и заказ «сдвинется» на несколько часов.
Ключевое различие — между датой и моментом времени. Дата рождения покупателя, дата действия акции «с 1 по 7 марта», дата поставки на склад — это календарные дни. Их передают как дату, без времени и зоны. Если превратить дату рождения в момент «полночь по Москве» и передать в UTC, получатель в другом поясе увидит предыдущий день. Время оформления заказа, время оплаты, время отгрузки — моменты. Их передают с зоной: в UTC или со смещением.
Практическое правило для магазина с точками в разных часовых поясах: моменты хранить и передавать в UTC (или со смещением), а в местное время переводить только при показе пользователю или в отчёте. При этом бизнес-правила вроде «заказ, оформленный до 14:00, отгружается сегодня» нужно явно привязать к часовому поясу — склада, магазина или покупателя. Это вопрос к бизнесу, и ответ на него должен быть в постановке.
Отдельно помните, что смещение и часовой пояс — не одно и то же. Смещение +03:00 — это число. Часовой пояс — правило, которое может включать переход на летнее время и меняться законом. Для будущих событий (доставка через месяц) иногда нужен именно пояс, например Europe/Moscow, а не смещение.
Кодировки
Компьютер хранит текст как последовательность байтов. Кодировка — таблица соответствия между символами и байтами. Сегодня стандарт де-факто — UTF-8: она вмещает символы всех языков, латиница в ней занимает один байт, кириллица два. До неё в русскоязычных системах использовались однобайтовые кодировки, прежде всего Windows-1251, и они до сих пор живут в старых учётных системах и файловых выгрузках.
«Кракозябры» появляются, когда текст записали в одной кодировке, а прочитали в другой. Байты при этом не испорчены — неправильно выбрана таблица. Слово «Привет», записанное в UTF-8 и прочитанное как Windows-1251, выглядит как Привет — характерное чередование «Р» и «С». Если же вместо букв видны знаки вопроса, текст, скорее всего, уже был необратимо испорчен при сохранении. Ромбики � обычно означают, что текст в однобайтовой кодировке читают как UTF-8; это ещё поправимо, если исходный файл цел.
Для требований это означает одно: кодировка указывается явно в каждом контракте — в заголовке Content-Type, в объявлении XML, в описании файлового обмена.
Отсутствует, null и пусто
У поля есть три разных состояния, и путать их — частый источник дефектов.
| Состояние | Пример в JSON | Типичный смысл |
|---|---|---|
| Поле отсутствует | ключа promoCode нет |
Отправитель ничего не сообщает об этом поле |
| Поле равно null | "promoCode": null |
Значения явно нет |
| Пустая строка | "promoCode": "" |
Значение есть, и это пустой текст |
Разница особенно важна при изменении данных. Представьте запрос на частичное изменение заказа (PATCH из модуля А.2). Если поле comment отсутствует — комментарий не трогаем. Если "comment": null — по распространённому соглашению (так устроен, например, стандарт JSON Merge Patch) удаляем имеющийся комментарий. Если "" — в зависимости от соглашения либо тоже удаляем, либо записываем пустой. Если это не описано, разработчики каждой стороны решат по-своему.
Поэтому для каждого поля в постановке нужно определить: обязательно ли оно (должно ли присутствовать), допускает ли null и допускает ли пустое значение, и что каждый из вариантов означает для бизнеса.
Схема данных
Пример сообщения показывает, как данные выглядят в одном случае. Он не говорит, какие поля обязательны, какие значения допустимы, какой максимальной длины строка и что будет, если позиций ноль. Схема данных — формальное описание всех допустимых сообщений, которое может проверять программа.
Для JSON используют JSON Schema, для XML — XSD (XML Schema Definition). Фрагмент JSON Schema для позиции заказа:
{
"type": "object",
"required": ["productId", "quantity", "price"],
"properties": {
"productId": { "type": "integer" },
"sku": { "type": "string", "maxLength": 20, "pattern": "^[0-9]+$" },
"quantity": { "type": "integer", "minimum": 1 },
"price": { "type": "string", "pattern": "^[0-9]+\\.[0-9]{2}$" }
},
"additionalProperties": false
}
Схема говорит: три поля обязательны, количество — целое не меньше единицы, цена — строка с ровно двумя знаками после точки, артикул — только цифры, не длиннее 20 символов, других полей быть не должно.
Что это даёт:
- однозначность — спорные вопросы из разделов выше закрыты формально, а не «как в примере»;
- автоматическая проверка — входящее сообщение можно проверить до обработки и вернуть понятную ошибку 400 или 422;
- генерация — по схеме можно создать код, документацию и тестовые данные.
Схема не заменяет описания смысла полей: она скажет, что status — строка из списка, но не объяснит, когда заказ переходит в SHIPPED. Как схемы встраиваются в описание API, разбирается в модулях А.6 и Б.3.
Разбор: заказ уходит в службу доставки
Магазин передаёт заказ службе доставки. Первые дни в продуктиве приносят три дефекта.
- У части заказов наложенный платёж на копейку отличается от суммы в магазине. Причина: сумма передавалась числом с плавающей точкой и пересчитывалась с округлением на стороне доставки. Исправление: сумма строкой с двумя знаками и явное правило округления.
- Заказы, оформленные вечером, попадают в отгрузку следующего дня, хотя должны уходить сегодня. Причина: время передавалось без зоны, служба доставки считала его своим местным, а у неё другой пояс. Исправление: момент со смещением или в UTC и правило «до 14:00 по времени склада».
- У заказов без комментария служба доставки печатает в накладной слово «null». Причина: магазин передаёт
"comment": null, а получатель ждёт отсутствия поля или пустой строки. Исправление: зафиксировать в контракте, что означает каждое состояние.
Ни одна из этих ошибок не в бизнес-логике. Все три закрывала бы таблица полей с типами, форматами и обязательностью.
Что дальше
За рамками урока осталось хранение данных в таблицах базы (модуль А.4), описание API целиком как контракта (А.6 и Б.3), обмен файлами большого объёма (8.4) и работа с XML в легаси-интеграциях и SOAP (8.6). Понятия схемы и структурированного вывода встретятся снова в модуле 5.1, когда речь пойдёт о языковых моделях.
Типичные ошибки
- Передавать деньги числом с плавающей точкой и не описывать валюту и правило округления.
- Передавать время без часового пояса или превращать календарную дату в момент времени.
- Описывать артикулы, телефоны и номера документов как числа, из-за чего теряются ведущие нули и знак «+».
- Не различать в требованиях отсутствующее поле, null и пустую строку.
- Не указывать кодировку и разделитель в требованиях к файловому обмену и надеяться на «стандартный CSV».
- Указывать длину строки без уточнения, в символах она или в байтах.
- Прикладывать к постановке только пример сообщения вместо таблицы полей или схемы.
Как говорить об этом на собеседовании
На junior/middle часто просят описать поле или сообщение и смотрят, какие вопросы кандидат задаёт сам. Сильный ответ на «как передать сумму заказа» — не просто «decimal», а связка: точный тип или строка, валюта, правило округления, сверка суммы позиций с итогом. На «как передать дату» — различие между датой и моментом, UTC или смещение, и к какому поясу привязаны бизнес-правила.
Хорошо работает пример из практики: интеграция, где дефект был в формате данных, а не в логике, и как его закрыла таблица полей или схема. Упоминание, что вы для каждого поля фиксируете тип, обязательность, допустимость null, формат и ограничения, показывает системный подход, который отличает системного аналитика от бизнес-аналитика.
Коротко
- JSON — объекты, массивы, строки, числа, логические значения и null; даты и деньги в нём передают строкой в оговорённом формате.
- XML — элементы, атрибуты и пространства имён; жив в банках, госинтеграциях и SOAP.
- CSV требует явного соглашения о разделителе, экранировании, заголовке, кодировке и форматах; Excel портит коды, длинные числа и даты.
- YAML — формат конфигураций, где ошибка в отступе или незакавыченное значение меняет смысл.
- Деньги — десятичная строка или целое в минимальных единицах, с валютой и правилом округления, но не float.
- Дата и момент времени — разные типы; моменты передают в UTC или со смещением по ISO 8601.
- «Кракозябры» — текст прочитан не в той кодировке; кодировку указывают в каждом контракте.
- Отсутствие поля, null и пустое значение — три состояния, смысл каждого фиксируется в постановке, а схема данных делает контракт проверяемым.
Читать дальше
- Спецификация JSON: json.org — одна страница с полной грамматикой.
- JSON Schema: раздел «Getting Started» на json-schema.org.
- Стандарт ISO 8601 — обзор в любой справочной статье.
Практика
- Описать в JSON обезличенный заказ интернет-магазина: покупатель, адрес доставки, 2–3 позиции, скидка, итог. Затем то же самое в XML. Сравнить.
- Составить таблицу полей этого заказа: имя, тип, обязательность, формат, пример, ограничения. Отдельно продумать деньги, даты и статусы.
- Открыть в Excel CSV-файл с номерами телефонов, артикулами с ведущими нулями и датами. Посмотреть, что испортилось, и записать правила файлового обмена, которые это предотвращают.
Вопросы для самопроверки
- Какие типы значений есть в JSON?
- Почему денежные суммы нельзя передавать как числа с плавающей точкой и как их передают?
- Как правильно передать дату и время заказа, если магазины находятся в разных часовых поясах?
- Чем отличаются отсутствующее поле, поле со значением null и пустая строка?
- Какие проблемы возникают при обмене CSV-файлами и как их предотвратить в требованиях?
- Зачем нужна схема данных, если есть пример сообщения?