Формирование JSON в 1С:Предприятии 8.3 — от ручной записи до сериализации

· 9 мин

Содержание

JSON в 1С формируют двумя инструментами платформы 8.3. Первый — объект ЗаписьJSON: он пишет документ поток за потоком, вы сами открываете объект, перечисляете свойства и закрываете структуру. Второй — глобальная функция ЗаписатьJSON, которая сериализует готовую Структуру, Соответствие или Массив целиком одной строкой кода.

Оба способа доступны из коробки, без внешних компонент и библиотек. Ручная запись нужна там, где форма выгрузки строго задана партнёром по обмену. Сериализация удобнее, когда данные уже собраны в коллекцию и их достаточно просто отдать «как есть». Ниже — рабочий код для обоих, выгрузка реквизитов справочника, вложенные массивы и разбор двух больных мест: кириллицы в \u-кодах и дат, которых в JSON нет.

Ручная или автоматическая запись: что выбрать под задачу

Выбор способа зависит от того, кто диктует формат файла и сколько в нём нестандартных полей.

Как формировать JSON под вашу задачу?

На практике чаще побеждает сериализация: собрать Структуру и отдать её функции быстрее, чем расставлять ЗаписатьНачалоОбъекта вручную. Ручной режим остаётся для потоковой выгрузки больших объёмов и для форматов, где важен точный порядок полей.

Пишем JSON вручную объектом ЗаписьJSON

Низкоуровневый способ. Вы создаёте объект, направляете вывод в строку или файл и вызываете методы записи по одному.

Минимальный пример — объект с тремя полями:

Запись = Новый ЗаписьJSON;
Запись.УстановитьСтроку();

Запись.ЗаписатьНачалоОбъекта();

Запись.ЗаписатьИмяСвойства("Код");
Запись.ЗаписатьЗначение("000012");

Запись.ЗаписатьИмяСвойства("Наименование");
Запись.ЗаписатьЗначение("ООО Ромашка");

Запись.ЗаписатьИмяСвойства("Активен");
Запись.ЗаписатьЗначение(Истина);

Запись.ЗаписатьКонецОбъекта();

Результат = Запись.Закрыть();

На выходе в переменной Результат строка:

{"Код":"000012","Наименование":"ООО Ромашка","Активен":true}

Разберём ключевые методы:

  • 🔹 УстановитьСтроку() — вывод пойдёт в строку, которую вернёт Закрыть().
  • 🔹 ОткрытьФайл(ИмяФайла) — вместо строки пишем сразу в файл на диске.
  • 🔹 ЗаписатьНачалоОбъекта() / ЗаписатьКонецОбъекта() — открывающая и закрывающая фигурные скобки { и }.
  • 🔹 ЗаписатьИмяСвойства(Имя) — имя ключа; сразу после него идёт значение.
  • 🔹 ЗаписатьЗначение(Значение) — записывает примитив: строку, число, булево или null (если передать Неопределено).
  • 🔹 Закрыть() — завершает запись; при выводе в строку возвращает результат.

Если вывод направлен в файл через ОткрытьФайл, метод Закрыть() ничего не возвращает — он просто закрывает файл. Строку в этом случае читать неоткуда: данные уже на диске.

Каждому ЗаписатьНачалоОбъекта обязан соответствовать ЗаписатьКонецОбъекта. Если забыть закрывающий вызов, Закрыть() выбросит исключение о незавершённой структуре.

Сериализация структуры и соответствия одной командой

Когда данные уже собраны в коллекцию, ручная запись лишняя. Глобальная функция ЗаписатьJSON обходит коллекцию сама и превращает её в JSON.

Данные = Новый Структура;
Данные.Вставить("Код", "000012");
Данные.Вставить("Наименование", "ООО Ромашка");
Данные.Вставить("Активен", Истина);

Запись = Новый ЗаписьJSON;
Запись.УстановитьСтроку();

ЗаписатьJSON(Запись, Данные);

Результат = Запись.Закрыть();

Результат тот же, что и в ручном примере, но кода втрое меньше. Правила преобразования простые:

Тип в 1СВо что превращается
Структураобъект {...}, ключи — имена свойств
Соответствиеобъект {...}, ключи — ключи соответствия
Массивмассив [...]
Строка, Число, Булевострока, число, true/false
Неопределеноnull

Разница между Структурой и Соответствием важна. Ключом Структуры может быть только корректный идентификатор — без пробелов, точек и кириллицы в начале. Если внешняя система ждёт поле user-id или Дата продажи, используйте Соответствие:

Данные = Новый Соответствие;
Данные.Вставить("user-id", 42);
Данные.Вставить("Дата продажи", "2024-05-01");

Вложенность работает автоматически: положите в структуру другую структуру или массив — функция развернёт их рекурсивно, на любую глубину.

Как выгрузить реквизиты справочника или документа

Прямо сериализовать ссылку на элемент справочника нельзя: ЗаписатьJSON знает только о примитивах и коллекциях. Поэтому реквизиты объекта сначала перекладывают в Структуру, а уже её передают функции.

Для одного объекта с известным составом полей:

Объект = Справочник.Контрагенты.НайтиПоКоду("000012").ПолучитьОбъект();

Данные = Новый Структура;
Данные.Вставить("Код", Объект.Код);
Данные.Вставить("Наименование", Объект.Наименование);
Данные.Вставить("ИНН", Объект.ИНН);

Запись = Новый ЗаписьJSON;
Запись.УстановитьСтроку();
ЗаписатьJSON(Запись, Данные);
Выгрузка = Запись.Закрыть();

Если полей много и перечислять их лень, пройдите по метаданным объекта и соберите реквизиты в цикле:

Данные = Новый Структура;
Для Каждого Реквизит Из Объект.Метаданные().Реквизиты Цикл
    Значение = Объект[Реквизит.Имя];
    Данные.Вставить(Реквизит.Имя, Значение);
КонецЦикла;

Здесь есть подвох: реквизит может оказаться ссылкой на другой объект, а ссылку сериализовать нельзя. Перед записью приводите такие значения к примитиву — к коду, наименованию или уникальному идентификатору: Значение.УникальныйИдентификатор() или Строка(Значение). Иначе функция выбросит исключение о неподдерживаемом типе.

Табличную часть документа выгружают так же: обходят строки, собирают каждую в структуру и складывают структуры в массив.

Полный рабочий сценарий — выгрузить результат запроса в файл. Запрос отдаёт выборку, каждую строку кладём в структуру, структуры копим в массив и сериализуем разом:

Запрос = Новый Запрос;
Запрос.Текст =
    "ВЫБРАТЬ Код, Наименование, ИНН
    |ИЗ Справочник.Контрагенты
    |ГДЕ НЕ ПометкаУдаления";
Выборка = Запрос.Выполнить().Выбрать();

Список = Новый Массив;
Пока Выборка.Следующий() Цикл
    Элемент = Новый Структура;
    Элемент.Вставить("Код", Выборка.Код);
    Элемент.Вставить("Наименование", Выборка.Наименование);
    Элемент.Вставить("ИНН", Выборка.ИНН);
    Список.Добавить(Элемент);
КонецЦикла;

Запись = Новый ЗаписьJSON;
Запись.ОткрытьФайл("c:\exchange\contragents.json");
ЗаписатьJSON(Запись, Список);
Запись.Закрыть();

На выходе — файл с массивом объектов, по одному на контрагента. Та же схема работает для табличной части: вместо выборки запроса обходите Документ.Товары и собирайте строки в массив структур.

Массивы, таблицы и вложенные коллекции

Коллекции в JSON — это массив [...]. В ручном режиме его открывают и закрывают явно:

Запись.ЗаписатьИмяСвойства("Телефоны");
Запись.ЗаписатьНачалоМассива();
Запись.ЗаписатьЗначение("+7 495 000-00-00");
Запись.ЗаписатьЗначение("+7 495 111-11-11");
Запись.ЗаписатьКонецМассива();

При сериализации достаточно вложить Массив в структуру — скобки расставятся сами:

Товары = Новый Массив;

Строка1 = Новый Структура("Номенклатура, Количество", "Карандаш", 10);
Строка2 = Новый Структура("Номенклатура, Количество", "Тетрадь", 5);
Товары.Добавить(Строка1);
Товары.Добавить(Строка2);

Документ = Новый Структура;
Документ.Вставить("Номер", "РН-0001");
Документ.Вставить("Товары", Товары);

Запись = Новый ЗаписьJSON;
Запись.УстановитьСтроку();
ЗаписатьJSON(Запись, Документ);
Результат = Запись.Закрыть();

Получится документ с массивом объектов внутри:

{"Номер":"РН-0001","Товары":[{"Номенклатура":"Карандаш","Количество":10},{"Номенклатура":"Тетрадь","Количество":5}]}

Так выгружают табличные части, результаты запросов и любые списки строк. Таблицу значений обходят методом Для Каждого Строка Из ТаблицаЗначений Цикл, собирая каждую строку в структуру по колонкам.

Кодировка, кириллица и спецсимволы

Два вопроса, на которых спотыкаются чаще всего, — «почему русский текст стал \u0420\u043E...» и «как записать дату».

Кириллица в \u-кодах. По умолчанию ЗаписьJSON экранирует все символы вне ASCII. Текст остаётся корректным JSON, но нечитаемым. Чтобы русские буквы писались как есть, задайте параметры записи с отключённым экранированием:

Параметры = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Авто, Символы.Таб, Истина,
    ЭкранированиеСимволовJSON.Нет);
Запись.УстановитьСтроку(Параметры);

Файл JSON всегда в кодировке UTF-8 — это требование формата, менять её не нужно. Экранирование влияет только на то, записать ли кириллицу буквами или их \u-кодами; и то и другое читается любым корректным парсером.

Даты. В JSON нет типа «дата», поэтому ЗаписатьЗначение(Дата) в ручном режиме не сработает — метод принимает строку, число, булево или Неопределено. Дату сначала приводят к строке. Удобный вариант — формат ISO 8601 через XMLСтрока:

Запись.ЗаписатьИмяСвойства("Дата");
Запись.ЗаписатьЗначение(XMLСтрока(ТекущаяДата()));

При сериализации через ЗаписатьJSON вариант записи даты задаётся объектом НастройкиСериализацииJSON — передайте его третьим параметром функции, если нужен формат, отличный от принятого по умолчанию.

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

Размер файла и скорость выгрузки

Для обмена по сети размер и скорость заметны на больших объёмах. Несколько приёмов, которые реально помогают.

  • 📦 Убрать отступы. Переносы строк и табуляция удобны для чтения, но раздувают файл. Для передачи задайте ПереносСтрокJSON.Нет — JSON выйдет одной строкой, компактнее на 20–40%.
  • 🔁 Писать потоком, а не копить в памяти. Для десятков тысяч записей не собирайте одну гигантскую Структуру — открывайте ЗаписьJSON на файл через ОткрытьФайл и пишите строки по мере обхода данных. Память не вырастет на весь объём выгрузки.
  • 🧹 Не выгружать лишние поля. Собирайте в структуру только нужные реквизиты, а не все подряд через метаданные. Меньше полей — меньше файл и быстрее разбор на принимающей стороне.
  • ⚙️ Один объект записи на выгрузку. Не создавайте ЗаписьJSON в цикле по строкам — создайте один раз до цикла, а Закрыть() вызовите после.

Закрыть() вызывают ровно один раз в конце. Повторный вызов на уже закрытом объекте приведёт к ошибке.

Для компактной выгрузки без отступов и с читаемой кириллицей параметры комбинируют:

Параметры = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет, "", Ложь,
    ЭкранированиеСимволовJSON.Нет);
Запись.УстановитьСтроку(Параметры);

Что ломает выгрузку и как это поймать

Ошибки при формировании JSON — это почти всегда исключения во время выполнения, а не кривой результат. Платформа останавливается на первом же нарушении структуры или типа.

Диагностика: выберите симптом

На время отладки оборачивайте запись в Попытка … Исключение … КонецПопытки и выводите ОписаниеОшибки() — текст исключения прямо называет, на каком свойстве платформа споткнулась.

Частые вопросы

Чем `ЗаписьJSON` отличается от функции `ЗаписатьJSON`?
ЗаписьJSON — объект для ручной потоковой записи: вы открываете объекты и массивы вызовами методов. ЗаписатьJSON — глобальная функция, которая сериализует готовую коллекцию целиком. Функция работает поверх того же объекта записи, поэтому Новый ЗаписьJSON создают в обоих случаях.
Можно ли сразу записать JSON в файл на диске?
Да. Вместо УстановитьСтроку() вызовите Запись.ОткрытьФайл("c:\exchange\data.json"). Данные пойдут прямо в файл, а Закрыть() в этом случае ничего не вернёт — результат уже на диске.
Как прочитать JSON обратно в 1С?
Чтением занимается парный объект ЧтениеJSON и функция ПрочитатьJSON, которая восстанавливает Соответствие или Массив из строки или файла. Это отдельная задача со своими методами разбора.
Почему при сериализации структуры поля идут не в том порядке, что я вставлял?
Структура сохраняет порядок вставки свойств, и JSON пишется в этом же порядке. Если порядок «плавает», проверьте, не используется ли Соответствие — и помните, что сам стандарт JSON порядок ключей в объекте не гарантирует, принимающая сторона не должна на него опираться.
Что будет со значением `Неопределено` в структуре?
Оно запишется как null. Если поле не должно попадать в выгрузку вовсе, не добавляйте его в структуру — пропуск свойства и значение null для принимающей системы не одно и то же.