А.3 Данные и форматы: JSON, XML, CSV, типы данных

Зачем это аналитику

Половина дефектов в интеграциях — не в логике, а в данных: дата в другом формате, сумма строкой, пропущенное поле, другая кодировка, другой часовой пояс. Аналитик, который точно описывает формат каждого поля, снимает эти дефекты ещё на этапе постановки.

Готовность к модулю

Модуль опирается на темы ниже. Если какая-то из них незнакома или её вопросы для самопроверки даются с трудом, начните с неё.

Куда ведёт

Тема подробнее раскрывается в модулях:

Что понять

  • 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.

Разбор: заказ уходит в службу доставки

Магазин передаёт заказ службе доставки. Первые дни в продуктиве приносят три дефекта.

  1. У части заказов наложенный платёж на копейку отличается от суммы в магазине. Причина: сумма передавалась числом с плавающей точкой и пересчитывалась с округлением на стороне доставки. Исправление: сумма строкой с двумя знаками и явное правило округления.
  2. Заказы, оформленные вечером, попадают в отгрузку следующего дня, хотя должны уходить сегодня. Причина: время передавалось без зоны, служба доставки считала его своим местным, а у неё другой пояс. Исправление: момент со смещением или в UTC и правило «до 14:00 по времени склада».
  3. У заказов без комментария служба доставки печатает в накладной слово «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 — обзор в любой справочной статье.

Практика

  1. Описать в JSON обезличенный заказ интернет-магазина: покупатель, адрес доставки, 2–3 позиции, скидка, итог. Затем то же самое в XML. Сравнить.
  2. Составить таблицу полей этого заказа: имя, тип, обязательность, формат, пример, ограничения. Отдельно продумать деньги, даты и статусы.
  3. Открыть в Excel CSV-файл с номерами телефонов, артикулами с ведущими нулями и датами. Посмотреть, что испортилось, и записать правила файлового обмена, которые это предотвращают.

Вопросы для самопроверки

  1. Какие типы значений есть в JSON?
  2. Почему денежные суммы нельзя передавать как числа с плавающей точкой и как их передают?
  3. Как правильно передать дату и время заказа, если магазины находятся в разных часовых поясах?
  4. Чем отличаются отсутствующее поле, поле со значением null и пустая строка?
  5. Какие проблемы возникают при обмене CSV-файлами и как их предотвратить в требованиях?
  6. Зачем нужна схема данных, если есть пример сообщения?

Заметки