При создании гибких печатных форм (например, конструкторов договоров или дополнительных соглашений) перед разработчиком встает задача дать пользователям возможность корректировать макеты в режиме «1С:Предприятие». Нередко возникает идея выгрузить макет в XML и сохранить его в строковом реквизите справочника. Разберем технические особенности такого решения, выясним, почему хранение в виде 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С позволяет помещать объект ТабличныйДокумент в реквизит с типом ХранилищеЗначения напрямую, используя встроенное сжатие данных.
Разберем сохранение и чтение макета из реквизита справочника:
// Запись макета в реквизит справочника
ОбъектСправочника.ШаблонМакет = Новый ХранилищеЗначения(ТабДокумент, Новый СжатиеДанных(9));
ОбъектСправочника.Записать();
// Извлечение макета при формировании печати
ТабДокумент = ОбъектСправочника.ШаблонМакет.Получить();
Если ТабДокумент = Неопределено Тогда
ТабДокумент = Новый ТабличныйДокумент;
КонецЕсли;
В этом случае платформа сама сериализует объект во внутренний бинарный формат с максимальным сжатием. Это исключает синтаксические ошибки и экономит дисковое пространство.
Если макет загружается из внешнего файла .mxl в виде объекта ДвоичныеДанные, его можно прочитать в табличный документ без создания временных файлов на диске. Для этого задействуем механизм потоков платформы 1С:
// Чтение ДвоичныхДанных в ТабличныйДокумент через поток
ПотокДляЧтения = ДвоичныеДанныеМакета.ОткрытьПотокДляЧтения();
Макет = Новый ТабличныйДокумент;
Макет.Прочитать(ПотокДляЧтения);
ПотокДляЧтения.Закрыть();
// Обратная выгрузка ТабличногоДокумента в ДвоичныеДанные
ПотокВПамяти = Новый ПотокВПамяти;
Макет.Записать(ПотокВПамяти, ТипФайлаТабличногоДокумента.MXL);
ДвоичныеДанныеРезультат = ПотокВПамяти.ЗакрытьИПолучитьДвоичныеДанные();
Такой подход полностью исключает проблемы с правами доступа к каталогам временных файлов при работе в распределенном кластере серверов.
Когда макет редактируется пользователями, возникает риск случайного удаления именованных областей или параметров. Чтобы процедура печати не падала с аварийной ошибкой, необходимо применять безопасные алгоритмы заполнения.
Макет.ПолучитьОбласть("Шапка") используем поиск в коллекции:
ОбластьНайдена = (Макет.Области.Найти("Шапка") <> Неопределено);
Если ОбластьНайдена Тогда
Область = Макет.ПолучитьОбласть("Шапка");
// Вывод области
КонецЕсли;
Область.Параметры.НомерДоговора = "123") вызовет исключение, если пользователь удалил параметр из ячейки. Рекомендуется заполнять параметры групповым методом:
СтруктураДанных = Новый Структура;
СтруктураДанных.Вставить("НомерДоговора", "123");
СтруктураДанных.Вставить("ДатаДоговора", ТекущаяДатаСеанса());
ЗаполнитьЗначенияСвойств(Область.Параметры, СтруктураДанных);
Если цель разработки — дать пользователю простой инструмент сборки документов, рассмотрим еще несколько подходов:
{v8 Номер}, а подсистема печати автоматически заполняет и формирует печатную форму:
ДвоичныеДанныеМакета = ПолучитьМакет("ПФ_DOC_ДопСоглашение");
Макет = УправлениеПечатью.ИнициализироватьМакетОфисногоДокумента(ДвоичныеДанныеМакета, Неопределено);
ПечатнаяФорма = УправлениеПечатью.ИнициализироватьПечатнуюФорму(Неопределено, Макет.НастройкиСтраницыМакета, Макет);
ФорматированныйДокумент. Он позволяет редактировать текст пользователю прямо в окне программы без внешних редакторов, а параметры заменяются программно с помощью функций СтрШаблон() или СтрЗаменить().ТабличныйДокумент и элемент управления с установленным свойством ТолькоПросмотр = Ложь. Пользователь получает полнофункциональный табличный редактор прямо внутри 1С.