Как преобразовать ДанныеФормыСтруктура в обычную структуру в 1С

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

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

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

Почему не работает ДанныеФормыВЗначение?

Многие разработчики по логике вещей пытаются использовать встроенную функцию платформы и пишут конструкцию вида:


СтруктураПараметров = ДанныеФормыВЗначение(ЭтаФорма.Параметры, Тип("Структура"));

Однако при выполнении этой команды программа гарантированно "вылетает" с ошибкой несоответствия типов — для отладки подобных ошибок в режиме предприятия пригодится инструмент написания и отладки кода 1С. Выясним причину. Метод ДанныеФормыВЗначение предназначен платформой для конвертации исключительно в прикладные объекты (например, СправочникОбъект, ДокументОбъект, НаборЗаписей). Тип Структура относится к базовым универсальным коллекциям, и платформа просто не умеет распаковывать данные управляемой формы в этот тип напрямую. Более того, коллекция ДанныеФормыСтруктура не поддерживает стандартный перебор через Для Каждого Параметр Из Параметры Цикл, что делает невозможным простое копирование "в лоб".

Способ 1. Использование JSON-сериализации (Современный подход)

Начиная с версий платформы 8.3.7, самым лаконичным и быстрым способом является сериализация через JSON. Этот способ избавляет нас от написания громоздких циклов парсинга узлов.

Проанализируем алгоритм:

  1. Данные формы преобразуются в текстовую строку JSON.
  2. Полученная строка читается базовым методом ПрочитатьJSON(), который автоматически формирует из нее привычную нам Структуру (или Соответствие).
  3. При необходимости очищаем результат от служебных полей (например, от технического свойства XDTO, указывающего на тип).

Посмотрим на пример реализации данного подхода:


&НаСервере
Функция ПреобразоватьПараметрыВструктуруJSON(ПараметрыФормы)
    
    Запись = Новый ЗаписьJSON;
    Запись.УстановитьСтроку();
    
    // Сериализуем данные формы в JSON
    СериализаторXDTO.ЗаписатьJSON(Запись, ПараметрыФормы);
    СтрокаJSON = Запись.Закрыть();
    
    // Читаем обратно
    Чтение = Новый ЧтениеJSON;
    Чтение.УстановитьСтроку(СтрокаJSON);
    
    // Метод ПрочитатьJSON автоматически создаст структуру
    Результат = ПрочитатьJSON(Чтение);
    Чтение.Закрыть();
    
    // Удаляем служебное поле типа, если оно появилось
    Если Результат.Свойство("#type") Тогда
        Результат.Удалить("#type");
    КонецЕсли;
    
    Возврат Результат;
    
КонецФункции

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

Способ 2. Использование XML-сериализации и FastInfoset

Если по какой-то причине JSON-сериализация не подходит (например, используются старые версии платформы), мы можем сериализовать объект в XML или бинарный XML (FastInfoset), а затем программно разобрать узлы, чтобы получить список имен параметров.

Разберем по шагам готовое решение:


&НаКлиентеНаСервереБезКонтекста
Функция ПолучитьСтруктуруДанныхФормы(ДанныеФормы)
    
    Массив = Новый Массив;
    Массив.Добавить(ДанныеФормы);
    
    Запись = Новый ЗаписьFastInfoset;
    Запись.УстановитьДвоичныеДанные();
    СериализаторXDTO.ЗаписатьXML(Запись, Массив);
    
    Чтение = Новый ЧтениеFastInfoset;
    Чтение.УстановитьДвоичныеДанные(Запись.Закрыть());
    
    Результат = Новый Структура;
    
    Пока Чтение.Прочитать() Цикл
        Если Чтение.Имя = "field" И Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
            
            ИмяПоля = Чтение.ЗначениеАтрибута("nameRu");
            Если ИмяПоля = Неопределено Тогда
                ИмяПоля = Чтение.ЗначениеАтрибута("name");
            КонецЕсли;
            
            // Исключаем системные поля
            Если ИмяПоля <> Неопределено 
               И ИмяПоля <> "СтандартнаяКартинкаСтроки" 
               И ИмяПоля <> "СтрокаДинамическогоСписка.ГруппировкаСтроки" Тогда
                
                // Вставляем ключ и сразу получаем значение из исходных данных
                Результат.Вставить(ИмяПоля, ДанныеФормы[ИмяПоля]);
            КонецЕсли;
            
        КонецЕсли;
    КонецЦикла;
    
    Возврат Результат;
    
КонецФункции

В этом примере мы читаем структуру свойств, а затем сразу заполняем новую структуру реальными значениями, обращаясь к свойствам через квадратные скобки: ДанныеФормы[ИмяПоля].

Способ 3. Перебор реквизитов через Метаданные

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

Посмотрим на пример такого перебора:


МетаданныеТипа = Метаданные.НайтиПоТипу(ТипЗнч(дфс.Ссылка));
резСтруктура = Новый Структура;
резСтруктура.Вставить("Ссылка", дфс.Ссылка);

Для каждого Реквизит из МетаданныеТипа.Реквизиты Цикл
    резСтруктура.Вставить(Реквизит.Имя, дфс[Реквизит.Имя]);
КонецЦикла;

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

Способ 4. Архитектурный подход Библиотеки Стандартных Подсистем (БСП)

Чтобы вообще не сталкиваться с проблемой десериализации параметров при открытии формы, мы можем применить правильный архитектурный подход. В современных конфигурациях на базе БСП применяется хитрость: нужные параметры собираются в обычную структуру еще до открытия формы и передаются как одно из свойств-параметров.

Вместо того чтобы передавать ключи в корень параметров, мы создаем вложенную структуру:


// На стороне вызывающего кода
ПараметрыОткрытия = Новый Структура;
ДопПараметры = Новый Структура("Сотрудник, Подразделение", ТекущийСотрудник, ТекущееПодразделение);
ПараметрыОткрытия.Вставить("ДопПараметры", ДопПараметры);

ОткрытьФорму("Обработка.МояОбработка.Форма", ПараметрыОткрытия);

Тогда внутри формы в ПриСозданииНаСервере мы обращаемся к Параметры.ДопПараметры. Тип этого вложенного свойства останется Структура, и его не придется конвертировать — мы сможем сразу обойти его с помощью цикла Для Каждого.

Альтернативный вариант — использовать подписку на событие или обработчик в модуле менеджера ОбработкаПолученияФормы. Там мы можем скопировать оригинальную структуру параметров:


Процедура ОбработкаПолученияФормы(ВидФормы, Параметры, ВыбраннаяФорма, ДополнительнаяИнформация, СтандартнаяОбработка)
    Если ВидФормы = "ФормаОбъекта" Тогда
        // На этом этапе Параметры — это еще обычная структура
        ПараметрыСтруктура = ОбщегоНазначения.СкопироватьРекурсивно(Параметры);
        Параметры.Вставить("ПараметрыСтруктура", ПараметрыСтруктура);
    КонецЕсли;
КонецПроцедуры

Подводные камни при преобразовании

Используя методы сериализации (JSON или XML), помните об одной важной особенности: дублирование имен. Если в ДанныеФормыСтруктура окажутся свойства с одинаковыми именами (например, имя реквизита документа совпадает с именем табличной части, что допускается платформой в некоторых контекстах формы), то при вставке в Структуру они перезапишут друг друга. Коллекция Структура в 1С требует строгой уникальности ключей, поэтому в итоговую структуру попадет только последнее считанное значение.

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

← На главную