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