В процессе разработки часто возникает задача собрать воедино данные из нескольких источников, где текст представлен в формате ФорматированныйДокумент. Это может быть объединение нескольких описаний товаров, склейка протоколов или формирование сложного письма из шаблонов. Особенность объекта ФорматированныйДокумент заключается в том, что его нельзя объединить простым сложением или методом Добавить(), так как это сложный структурный объект, содержащий коллекции параграфов, текстовых элементов и картинок.
В данной статье мы подробно разберем, как решить эту задачу двумя основными способами: путем прямого перебора элементов структуры и с помощью конвертации в HTML. Мы проанализируем сильные и слабые стороны каждого метода, чтобы вы могли выбрать наиболее подходящий для вашего случая.
Этот метод считается наиболее «чистым», так как он работает напрямую с объектной моделью 1С, сохраняя внутренние свойства шрифтов, цветов и вложенных объектов без промежуточных преобразований. Разберем логику процесса: нам необходимо взять каждый параграф из исходного документа, создать аналогичный параграф в целевом документе и перенести в него все элементы (текст, переводы строк, картинки) со всеми их свойствами.
Проанализируем готовую процедуру, которая выполняет это копирование. Рассмотрим её по шагам:
Процедура СоединитьФорматированныеДокументы(ИсходныйДокумент, ДокументПолучатель) Экспорт
// Перебираем все верхнеуровневые элементы (параграфы) исходного документа
Для Каждого Параграф Из ИсходныйДокумент.Элементы Цикл
// Создаем новый параграф в документе-приемнике
НовыйПараграф = ДокументПолучатель.Элементы.Добавить();
// Копируем базовые свойства параграфа (выравнивание, отступы и тип)
ЗаполнитьЗначенияСвойств(НовыйПараграф, Параграф);
// Теперь переходим к внутреннему содержимому параграфа
Для Каждого ЭлементПараграфа Из Параграф.Элементы Цикл
Если Тип(ЭлементПараграфа) = Тип("ТекстФорматированногоДокумента") Тогда
// Добавляем текстовый фрагмент
НовыйТекст = НовыйПараграф.Элементы.Добавить(ЭлементПараграфа.Текст);
// Важно перенести все свойства оформления текста вручную
НовыйТекст.НавигационнаяСсылка = ЭлементПараграфа.НавигационнаяСсылка;
НовыйТекст.ЦветТекста = ЭлементПараграфа.ЦветТекста;
НовыйТекст.ЦветФона = ЭлементПараграфа.ЦветФона;
// Создаем новый объект Шрифт на основании старого
Если ЭлементПараграфа.Шрифт <> Неопределено Тогда
НовыйТекст.Шрифт = Новый Шрифт(ЭлементПараграфа.Шрифт);
КонецЕсли;
ИначеЕсли Тип(ЭлементПараграфа) = Тип("ПереводСтрокиФорматированногоДокумента") Тогда
// Просто добавляем разрыв строки внутри параграфа
НовыйПараграф.Элементы.Добавить(, Тип("ПереводСтрокиФорматированногоДокумента"));
ИначеЕсли Тип(ЭлементПараграфа) = Тип("КартинкаФорматированногоДокумента") Тогда
// Копируем картинку
НоваяКартинка = НовыйПараграф.Элементы.Добавить(ЭлементПараграфа.Картинка, Тип("КартинкаФорматированногоДокумента"));
// Переносим настройки отображения изображения
НоваяКартинка.НавигационнаяСсылка = ЭлементПараграфа.НавигационнаяСсылка;
НоваяКартинка.Ширина = ЭлементПараграфа.Ширина;
НоваяКартинка.Высота = ЭлементПараграфа.Высота;
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецПроцедуры
Важные замечания по коду:
ТипПараграфаФорматированногоДокумента (используемый для списков) полноценно доступен в толстом клиенте. При работе на сервере (особенно в старых версиях платформы до 8.3.12) могут возникать ошибки при попытке прямого сравнения типов параграфов. Используйте ЗаполнитьЗначенияСвойств для безопасного переноса типа.Шрифт у текста равно Неопределено, это означает использование стандартного шрифта формы. В этом случае попытка создания Новый Шрифт(Неопределено) вызовет ошибку, поэтому мы добавили проверку в коде выше.Если вам не хочется глубоко лезть в структуру элементов или документы содержат очень сложное форматирование, которое трудно воспроизвести перебором, можно воспользоваться промежуточным преобразованием в HTML. Этот метод кажется проще, но требует внимательности при работе с тегами.
Выясним причину, по которой обычная склейка HTML-строк может не сработать. Когда мы вызываем метод ПолучитьHTML(), 1С генерирует полный документ с тегами <html> и <body>. Если просто соединить две такие строки, мы получим некорректный код с двумя «головами» и «телами», что приведет к ошибкам визуализации.
Рассмотрим правильный алгоритм работы с HTML:
ПолучитьHTML(ТекстHTML, СтруктураКартинок).<body>.ФорматированныйДокумент методом УстановитьHTML().Пример кода для базовой установки данных через HTML:
// Пример получения HTML из формы (упрощенно)
СтруктураВложения = Новый Структура;
ТекстHTML = "";
ЭтаФорма.ПолеФорматированногоДокумента.ПолучитьHTML(ТекстHTML, СтруктураВложения);
// Пример установки накопленного HTML обратно
НовыйДокумент = Новый ФорматированныйДокумент;
НовыйДокумент.УстановитьHTML(ОбъединенныйТекстHTML, ОбщаяСтруктураВложений);
Проанализируем ситуацию, описанную разработчиками на форумах: иногда при добавлении нескольких маркированных или нумерованных списков подряд платформа начинает вести себя непредсказуемо (например, «склеивает» разные списки в один или игнорирует смену типа нумерации). Это часто связано с тем, как 1С интерпретирует последовательность параграфов одного типа.
Чтобы избежать подобных проблем, при программном объединении рекомендуется:
Обычный. Это сбросит состояние счетчика нумерации и визуально разделит блоки текста.Выберем подходящий инструмент в зависимости от ваших задач:
Метод перебора элементов (Способ 1):
— Плюсы: Высокая точность, отсутствие лишнего «мусора» от HTML-разметки, надежная работа с картинками как с объектами платформы.
— Минусы: Требует написания большего объема кода, необходимо вручную обрабатывать каждый тип элемента (текст, картинка, перевод строки).
Метод HTML-трансформации (Способ 2):
— Плюсы: Легко реализовать «быструю» склейку, если не пугают теги.
— Минусы: Возможны потери специфического форматирования 1С, риск получить некорректный HTML-код, сложности с объединением вложений (картинок) из разных документов.
Подводя итог, можно сказать, что для задач внутри базы 1С (например, формирование текста письма из нескольких реквизитов справочника) оптимальным является первый способ. Он гарантирует, что итоговый ФорматированныйДокумент останется валидным объектом платформы и будет корректно отображаться в любых формах и отчетах.