Как хранить и восстанавливать пользовательские макеты печати в 1С: XML-строка или ХранилищеЗначения?

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

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

Вариант 1. Преобразование выгруженного текста XML обратно в табличный документ

Если структура решения уже завязана на выгрузку табличного документа в XML-формат платформы (пространство имен http://v8.1c.ru/8.2/data/spreadsheet), восстановить объект можно с помощью механизма XDTO-сериализации.

Обратите внимание, что стандартная функция глобального контекста XMLСтрока() не поддерживает объект ТабличныйДокумент напрямую и вызовет исключение. Преобразование выполняется строго через СериализаторXDTO и объект ЧтениеXML.

Посмотрим на пример функции, восстанавливающей табличный документ из строкового XML:


Функция ВосстановитьМакетИзXML(ТекстXML)
    Чтение = Новый ЧтениеXML;
    Чтение.УстановитьСтроку(ТекстXML);
    
    Попытка
        ТабДок = СериализаторXDTO.ПрочитатьXML(Чтение, Тип("ТабличныйДокумент"));
    Исключение
        Чтение.Закрыть();
        ВызватьИсключение "Ошибка десериализации макета: " + ОписаниеОшибки();
    КонецПопытки;
    
    Чтение.Закрыть();
    Возврат ТабДок;
КонецФункции

Обратная операция — сохранение табличного документа в XML-строку — выполняется симметрично через объект ЗаписьXML:


Функция ПолучитьXMLИзМакета(ТабДок)
    Запись = Новый ЗаписьXML;
    Запись.УстановитьСтроку();
    
    СериализаторXDTO.ЗаписатьXML(Запись, ТабДок);
    
    РезультатXML = Запись.Закрыть();
    Возврат РезультатXML;
КонецФункции

Подводные камни работы с XML-строкой:

  1. Чувствительность к синтаксису: структура макета 1С содержит сложное дерево стилей, границ, шрифтов и ячеек. Если пользователь или алгоритм случайно повредит хотя бы один закрывающий тег, макет не восстановится.
  2. Неэффективное хранение: текст неограниченной длины в таблицах СУБД хранится в отдельных blob-страницах без системного сжатия, что раздувает объем информационной базы.

Вариант 2. Хранение в реквизите типа «ХранилищеЗначения» (рекомендуемый способ)

Проанализируем более производительный вариант. Платформа 1С позволяет помещать объект ТабличныйДокумент в реквизит с типом ХранилищеЗначения напрямую, используя встроенное сжатие данных.

Разберем сохранение и чтение макета из реквизита справочника:


// Запись макета в реквизит справочника
ОбъектСправочника.ШаблонМакет = Новый ХранилищеЗначения(ТабДокумент, Новый СжатиеДанных(9));
ОбъектСправочника.Записать();

// Извлечение макета при формировании печати
ТабДокумент = ОбъектСправочника.ШаблонМакет.Получить();
Если ТабДокумент = Неопределено Тогда
    ТабДокумент = Новый ТабличныйДокумент;
КонецЕсли;

В этом случае платформа сама сериализует объект во внутренний бинарный формат с максимальным сжатием. Это исключает синтаксические ошибки и экономит дисковое пространство.

Вариант 3. Работа с двоичными данными через потоки в памяти

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


// Чтение ДвоичныхДанных в ТабличныйДокумент через поток
ПотокДляЧтения = ДвоичныеДанныеМакета.ОткрытьПотокДляЧтения();
Макет = Новый ТабличныйДокумент;
Макет.Прочитать(ПотокДляЧтения);
ПотокДляЧтения.Закрыть();

// Обратная выгрузка ТабличногоДокумента в ДвоичныеДанные
ПотокВПамяти = Новый ПотокВПамяти;
Макет.Записать(ПотокВПамяти, ТипФайлаТабличногоДокумента.MXL);
ДвоичныеДанныеРезультат = ПотокВПамяти.ЗакрытьИПолучитьДвоичныеДанные();

Такой подход полностью исключает проблемы с правами доступа к каталогам временных файлов при работе в распределенном кластере серверов.

Обеспечение отказоустойчивости при заполнении пользовательских макетов

Когда макет редактируется пользователями, возникает риск случайного удаления именованных областей или параметров. Чтобы процедура печати не падала с аварийной ошибкой, необходимо применять безопасные алгоритмы заполнения.

  1. Проверка областей на существование: вместо прямого вызова Макет.ПолучитьОбласть("Шапка") используем поиск в коллекции:
    
    ОбластьНайдена = (Макет.Области.Найти("Шапка") <> Неопределено);
    Если ОбластьНайдена Тогда
        Область = Макет.ПолучитьОбласть("Шапка");
        // Вывод области
    КонецЕсли;
    
  2. Безопасное заполнение параметров: прямое обращение к свойству (например, Область.Параметры.НомерДоговора = "123") вызовет исключение, если пользователь удалил параметр из ячейки. Рекомендуется заполнять параметры групповым методом:
    
    СтруктураДанных = Новый Структура;
    СтруктураДанных.Вставить("НомерДоговора", "123");
    СтруктураДанных.Вставить("ДатаДоговора", ТекущаяДатаСеанса());
    
    ЗаполнитьЗначенияСвойств(Область.Параметры, СтруктураДанных);
    

Альтернативные архитектурные решения

Если цель разработки — дать пользователю простой инструмент сборки документов, рассмотрим еще несколько подходов:

  1. Использование шаблонов Microsoft Word (DOCX) через БСП: в библиотеке стандартных подсистем реализован готовый механизм офисных макетов. В шаблоне документа определяются области и теги вида {v8 Номер}, а подсистема печати автоматически заполняет и формирует печатную форму:
    
    ДвоичныеДанныеМакета = ПолучитьМакет("ПФ_DOC_ДопСоглашение");
    Макет = УправлениеПечатью.ИнициализироватьМакетОфисногоДокумента(ДвоичныеДанныеМакета, Неопределено);
    ПечатнаяФорма = УправлениеПечатью.ИнициализироватьПечатнуюФорму(Неопределено, Макет.НастройкиСтраницыМакета, Макет);
    
  2. Форматированный документ: если документ представляет собой сплошной текст с пунктами и форматированием (жирный, курсив, списки), можно использовать объект ФорматированныйДокумент. Он позволяет редактировать текст пользователю прямо в окне программы без внешних редакторов, а параметры заменяются программно с помощью функций СтрШаблон() или СтрЗаменить().
  3. Интерактивное редактирование таблицы: на форму справочника можно поместить реквизит типа ТабличныйДокумент и элемент управления с установленным свойством ТолькоПросмотр = Ложь. Пользователь получает полнофункциональный табличный редактор прямо внутри 1С.
← На главную