Как выгрузить иерархический справочник в JSON с сохранением вложенности?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В современной разработке часто возникает задача передачи данных из 1С во внешние системы (веб-сайты, мобильные приложения, сторонние API). Одной из наиболее трудоемких задач является сохранение древовидной структуры иерархических справочников при конвертации в формат JSON. В этой статье мы подробно разберем, как правильно сформировать вложенный JSON, чтобы структура "Папка - Подпапка - Элемент" сохранилась в исходном виде.

Метод 1: Использование «Дерева значений» и рекурсии

Это классический и наиболее гибкий способ. Его суть заключается в том, что мы сначала получаем данные из 1С в виде системного объекта ДеревоЗначений, который уже содержит иерархию, а затем рекурсивно обходим его для формирования структуры JSON. Рассмотрим этот процесс пошагово.

Шаг 1: Получение данных. Для начала нам необходимо составить запрос, который выберет элементы справочника с учетом их подчиненности. Важно использовать итоги по иерархии, чтобы платформа сама выстроила дерево.


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Номенклатура.Ссылка КАК Ссылка,
    |   Номенклатура.Наименование КАК Наименование,
    |   Номенклатура.ЭтоГруппа КАК ЭтоГруппа
    |ИЗ
    |   Справочник.Номенклатура КАК Номенклатура
    |ИТОГИ ПО
    |   Ссылка ИЕРАРХИЯ";

Дерево = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);

Шаг 2: Рекурсивное преобразование. Теперь напишем функцию, которая будет превращать строки дерева значений в массив структур. Каждая структура будет представлять собой элемент справочника, а если у него есть вложенные элементы, они попадут в массив items внутри этой структуры.


Функция ДеревоВМассив(СтрокиДерева)
    МассивРезультат = Новый Массив;
    
    Для Каждого СтрокаДерева Из СтрокиДерева Цикл
        СтруктураОбъекта = Новый Структура;
        СтруктураОбъекта.Вставить("id", Строка(СтрокаДерева.Ссылка.УникальныйИдентификатор()));
        СтруктураОбъекта.Вставить("name", СтрокаДерева.Наименование);
        СтруктураОбъекта.Вставить("isFolder", СтрокаДерева.ЭтоГруппа);
        
        // Рекурсивный вызов для подчиненных строк
        Если СтрокаДерева.Строки.Количество() > 0 Тогда
            СтруктураОбъекта.Вставить("items", ДеревоВМассив(СтрокаДерева.Строки));
        Иначе
            СтруктураОбъекта.Вставить("items", Новый Массив);
        КонецЕсли;
        
        МассивРезультат.Добавить(СтруктураОбъекта);
    КонецЦикла;
    
    Возврат МассивРезультат;
КонецФункции

Шаг 3: Запись в JSON. Полученный массив структур легко сериализуется стандартными средствами платформы.


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

Метод 2: Сборка дерева через «Соответствие» (Map)

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

Алгоритм действий следующий:

  1. Выгружаем все нужные элементы справочника в плоский список (таблицу значений).
  2. Для каждого элемента создаем Структура, где будут храниться его данные и пустой массив для будущих детей.
  3. Все структуры помещаем в Соответствие, где ключом выступает Ссылка элемента.
  4. Вторым проходом по списку определяем родителя каждого элемента. Если родитель есть в нашем соответствии, мы просто добавляем текущую структуру в массив "Дети" структуры родителя.

Этот метод позволяет избежать рекурсии и собрать дерево за фиксированное время, пропорциональное количеству элементов.

Особенности сериализации типов данных 1С

При выгрузке в JSON мы часто сталкиваемся с тем, что стандартная функция ЗаписатьJSON не знает, как обрабатывать специфические типы, такие как СправочникСсылка или УникальныйИдентификатор. Разберем, как решить эту проблему.

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


Настройки = Новый НастройкиСериализацииJSON;
Настройки.ВариантЗаписиДаты = ВариантЗаписиДатыJSON.ISO;
// Пример обработки ссылки
// В коде функции-обработчика:
// Если ТипЗнч(Значение) = Тип("СправочникСсылка.Номенклатура") Тогда
//     Возврат Строка(Значение.УникальныйИдентификатор());
// КонецЕсли;

Важный момент: всегда приводите ссылки к строковому представлению их GUID. Если просто передать ссылку в структуру, сериализатор может выдать системную строку вида {"Ref": "..."}, что не всегда удобно для внешних систем.

Альтернативный подход: Плоский список с идентификатором родителя

Стоит рассмотреть ситуацию, когда принимающая сторона (например, современный веб-фронтенд на React или Vue) предпочитает получать не вложенную структуру, а плоский массив объектов. В этом случае каждый объект должен содержать поля id и parentId.

Выясним преимущества такого подхода:

Для реализации этого метода достаточно выгрузить результат запроса в таблицу значений и сериализовать её как массив структур, не заботясь о вложенности на стороне 1С.

Предотвращение зацикливания

При работе с иерархией в 1С (особенно в старых базах или после некорректных обменов) возможна ситуация "зацикливания", когда элемент является родителем самого себя. Рассмотрим, как этого избежать. При использовании рекурсивного метода 1 (через ДеревоЗначений) платформа сама контролирует иерархию, и бесконечный цикл маловероятен. Однако при ручной сборке дерева рекомендуется вести список уже обработанных ссылок. Если ссылка встречается повторно в одной ветке — это сигнал о критической ошибке в данных, которую нужно обработать исключением или пропустить элемент.

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

← На главную