Как преобразовать дерево значений в структуру и массив для сериализации в JSON в 1С?

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

При подготовке иерархических данных (например, справочника «Номенклатура» с произвольной вложенностью) к передаче во внешние системы или сериализации в формат JSON часто возникает необходимость обхода дерева значений с его конвертацией в контейнеры 1С. В процессе разработки рекурсивной функции разработчики часто сталкиваются с проблемой: объект Структура затирает ранее внесенные элементы, если они находятся на одном уровне иерархии или привязываются к одному и тому же родительскому ключу.

Рассмотрим, почему возникает эта проблема, как устроена работа с иерархическими контейнерами данных в 1С и какими способами можно корректно преобразовать дерево в формат, готовый к выгрузке в JSON.

Выясним причину: почему Структура затирает данные первого уровня

Объект Структура в платформе 1С представляет собой коллекцию пар «Ключ - Значение». Главное ограничение этого объекта заключается в том, что имена ключей должны быть уникальными и соответствовать правилам именования идентификаторов. При попытке вызвать метод Вставить() с уже существующим ключом старое значение не добавляется рядом, а полностью перезаписывается новым.

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

Решение 1: Использование массива структур (Массив + Структура)

Чтобы избежать перезаписи узлов одного уровня, разберем базовый подход: представление каждого узла иерархии в виде отдельной структуры, а списка подчиненных элементов — в виде массива таких структур.

Проанализируем структуру будущего объекта:

  1. Каждый элемент дерева (группа или элемент) описывается объектом Структура. В ней содержатся реквизиты (например, Код, Наименование, ЭтоГруппа).
  2. Если у элемента есть подчиненные строки, в структуру добавляется ключ Элементы (или Содержимое), значением которого является Массив.
  3. В этот массив рекурсивно добавляются структуры дочерних элементов.

Посмотрим на пример реализации рекурсивной функции на сервере для объекта ДеревоЗначений:


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

После получения такого массива его легко сериализовать в JSON с помощью штатной функции ЗаписатьJSON():


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

// Записываем сформированный массив структур
ЗаписатьJSON(ЗаписьJSON, СформированныйМассив);

СтрокаJSON = ЗаписьJSON.Закрыть();

При таком подходе итоговый JSON будет содержать валидную древовидную структуру вида [{"Код": "001", "Элементы": [...]}], которая легко разбирается на стороне любого внешнего сервиса аналогичной рекурсивной функцией.

Решение 2: Потоковая запись напрямую в JSON через ЗаписьJSON

Если дерево значений имеет очень большой объем и создание промежуточных объектов 1С (сотни тысяч структур и массивов) забивает оперативную память, проанализируем альтернативный вариант — прямое формирование JSON с помощью объекта ЗаписьJSON.

Разберем по шагам данный подход:

  1. Открываем запись JSON методом УстановитьСтроку() или ОткрытьФайл().
  2. Перед обходом коллекции открываем массив методом ЗаписатьНачалоМассива().
  3. Для каждого элемента формируем объект с помощью ЗаписатьНачалоОбъекта() и записываем его свойства через ЗаписатьИмяСвойства() и ЗаписатьЗначение().
  4. Если есть дочерние строки, рекурсивно вызываем процедуру записи внутри свойства Элементы.
  5. Закрываем объект и массив соответствующими методами ЗаписатьКонецОбъекта() и ЗаписатьКонецМассива().

Рассмотрим пример кода потоковой записи:


Процедура ЗаписатьДеревоВJSONРекурсивно(ЗаписьJSON, КоллекцияСтрок)
    
    ЗаписьJSON.ЗаписатьНачалоМассива();
    
    Для Каждого СтрокаДерева Из КоллекцияСтрок Цикл
        
        ЗаписьJSON.ЗаписатьНачалоОбъекта();
        
        ЗаписьJSON.ЗаписатьИмяСвойства("Код");
        ЗаписьJSON.ЗаписатьЗначение(СтрокаДерева.Код);
        
        ЗаписьJSON.ЗаписатьИмяСвойства("Наименование");
        ЗаписьJSON.ЗаписатьЗначение(СтрокаДерева.Наименование);
        
        ПодчиненныеСтроки = СтрокаДерева.Строки;
        Если ПодчиненныеСтроки.Количество() > 0 Тогда
            ЗаписьJSON.ЗаписатьИмяСвойства("Элементы");
            ЗаписатьДеревоВJSONРекурсивно(ЗаписьJSON, ПодчиненныеСтроки);
        КонецЕсли;
        
        ЗаписьJSON.ЗаписатьКонецОбъекта();
        
    КонецЦикла;
    
    ЗаписьJSON.ЗаписатьКонецМассива();
    
КонецПроцедуры

Особенности работы на Клиенте и Сервере

При написании процедур обхода иерархических данных обратим внимание на различия в типах объектов платформы 1С:

Учитывайте этот нюанс при переносе кода между клиентским и серверным контекстом исполняемого модуля.

← На главную