Вывод форматированного документа в формате Office open XML (WORD) через сервер с использованием БСП

08.02.24

Разработка - Инструментарий разработчика

Стаяла задача выводить много разных форматированных документов в ворд, пришлось для этого немного "покурить" Office Open XML.  У меня получилось следующее решение.

Скачать исходный код

Наименование Файл Версия Размер
Вывод форматированного документа в формате Office open XML (WORD) через сервер с использованием БСП.:
.epf 24,13Kb
2
.epf 24,13Kb 2 Скачать

В макете ворда делаем определенный тег для форматированного документа, у меня это  {v8 ФорматированныйДокумент}

Далее в коде после получения области

		Область = УправлениеПечатью.ОбластьМакета(Макет, Области[ИмяМакета].ТекстФорматированногоДокумента); 

Находим область и заменяем ее на наш сгенерированный xml код и присоединяем область.

		ТекстОбласти = Область.Текст;
		
		СтрокаПоискаБезТегов = "ФорматированныйДокумент"; 
		СтрокаПоиска = "{v8 " + СтрокаПоискаБезТегов + "}"; 
		
		НачалоОписания = СтрНайти(ТекстОбласти, СтрокаПоиска);    
		Описание = ЭтотОбъект.Описание;
		
		НомерКартинки = 0;
		
		Пока НачалоОписания <> 0 Цикл 
			
			ЗаменаОписанияНаХМЛ(НачалоОписания, ТекстОбласти, СтрокаПоиска, СтрокаПоискаБезТегов, 
			Описание, ДанныеОбъекта, НомерКартинки);
			
		КонецЦикла;        
		
		Область.Текст = ТекстОбласти;
		
		УправлениеПечатью.ПрисоединитьОбластьИЗаполнитьПараметры(ПечатнаяФорма, Область, ДанныеОбъекта);
Процедура ЗаменаОписанияНаХМЛ(НачалоОписания, ТекстОбласти, СтрокаПоиска, СтрокаПоискаБезТегов, Описание, ДанныеОбъекта, НомерКартинки)
	
    ТекстХМЛ = "";  
	ТекстИзменение = ТекстОбласти; 
	
	НачалоТекстаЗамены = СтрНайти(ТекстИзменение, "<w:p ", НаправлениеПоиска.СКонца, НачалоОписания);
	КонецТекстаЗамены = СтрНайти(ТекстИзменение, "</w:p>", НаправлениеПоиска.СНачала, НачалоОписания);
	Длина = КонецТекстаЗамены - НачалоТекстаЗамены;
	ТекстЗамены = Сред(ТекстИзменение, НачалоТекстаЗамены, Длина + 6);


	КонецПараграфа = СтрНайти(ТекстЗамены, ">");   
	Параграф = Лев(ТекстЗамены, КонецПараграфа);  
	
	НачалоСвойстваРаздела = СтрНайти(ТекстИзменение, "<w:pPr>", НаправлениеПоиска.СКонца);
	СвойстваРаздела = Сред(ТекстИзменение, НачалоСвойстваРаздела);  
	КонецСвойстваРаздела = СтрНайти(СвойстваРаздела, "</w:pPr>");   
	СвойстваРаздела = Лев(СвойстваРаздела, КонецСвойстваРаздела + 7); 
	
	ЗапускТекста = "<w:r>";
	Текст = "<w:t>";

	Для каждого ПараграфФорматированногоДокумента из Описание.Элементы Цикл
		ТекстХМЛ = ДобавитьТекст(ТекстХМЛ, Параграф); 
		ТекущееСвойствоРаздела = СвойстваРаздела;	
		Выравнивание = ПараграфФорматированногоДокумента.ГоризонтальноеПоложение; 

		Если Выравнивание <> ГоризонтальноеПоложение.Авто Тогда
			Центр = "center";  
			Лево = "left";
			Право = "right";
			ПоШирине = "both"; 
			
			Если Выравнивание = ГоризонтальноеПоложение.Лево Тогда
				ТекущиеВырванивание = Лево;		
			КонецЕсли; 
			
			Если Выравнивание = ГоризонтальноеПоложение.Право Тогда
				ТекущиеВырванивание = Право;		
			КонецЕсли;
			
			Если Выравнивание = ГоризонтальноеПоложение.Центр Тогда
				ТекущиеВырванивание = Центр;		
			КонецЕсли;  
			
			Если Выравнивание = ГоризонтальноеПоложение.ПоШирине Тогда
				ТекущиеВырванивание = ПоШирине;		
			КонецЕсли;
		
			НачалоСвойстваРаздела = СтрНайти(ТекущееСвойствоРаздела, "<w:jc w:val=""", НаправлениеПоиска.СКонца); 
			Если НачалоСвойстваРаздела <> 0  Тогда
				
				ВыравниваниеСвойства = Сред(ТекущееСвойствоРаздела, НачалоСвойстваРаздела + 13);  
				КонецСвойстваРаздела = СтрНайти(ВыравниваниеСвойства, """/>");   
				ВыравниваниеСвойства = Лев(ВыравниваниеСвойства, КонецСвойстваРаздела - 1); 
				ТекущееСвойствоРаздела = СтрЗаменить(ТекущееСвойствоРаздела, ВыравниваниеСвойства, ТекущиеВырванивание); 
				
			Иначе
				
				ВыравниваниеНовое = СтрШаблон("<w:jc w:val=""%1""/>", ТекущиеВырванивание);  
				ТекущееСвойствоРаздела = СтрЗаменить(ТекущееСвойствоРаздела, "<w:pPr>", "<w:pPr>" + ВыравниваниеНовое);
				
			КонецЕсли;
			
		КонецЕсли;    
		
		Если ПараграфФорматированногоДокумента.ТипПараграфа = ТипПараграфа.МаркированныйСписок Тогда
			
			НумерованныйСписок = "<w:pPr><w:numPr><w:ilvl w:val=""0""/><w:numId w:val=""1""/></w:numPr>";
			ТекущееСвойствоРаздела = СтрЗаменить(ТекущееСвойствоРаздела, "<w:pPr>", НумерованныйСписок);
			
		ИначеЕсли ПараграфФорматированногоДокумента.ТипПараграфа = ТипПараграфа.НумерованныйСписок Тогда
			
			НумерованныйСписок =  "<w:pPr><w:numPr><w:ilvl w:val=""0""/><w:numId w:val=""2""/></w:numPr>";
			ТекущееСвойствоРаздела = СтрЗаменить(ТекущееСвойствоРаздела, "<w:pPr>", НумерованныйСписок);
			
		КонецЕсли; 
		
		ТекстХМЛ = ДобавитьТекст(ТекстХМЛ, ТекущееСвойствоРаздела);
		
		Для каждого ЭлементыПараграфа Из ПараграфФорматированногоДокумента.Элементы Цикл
			
			
			ТипТексФД = Тип("ТекстФорматированногоДокумента");
			ТипКартинкаФД = Тип("КартинкаФорматированногоДокумента");
			ТипПереводСтрокиФД = Тип("ПереводСтрокиФорматированногоДокумента");
			ТекстХМЛ = ДобавитьТекст(ТекстХМЛ, ЗапускТекста);
			
			
			Если ТипЗнч(ЭлементыПараграфа) = ТипТексФД Тогда
								
				ТекстХМЛ = ДобавитьТекст(ТекстХМЛ, "<w:rPr>");

				Шрифт = ЭлементыПараграфа.Шрифт;   
				ЦветТекста = ЭлементыПараграфа.ЦветТекста; 
				ЦветФона = ЭлементыПараграфа.ЦветФона;  
				
				Если ЦветТекста <> Новый Цвет() Тогда
					
					РГБЦвет = ЦветТекста.ПолучитьАбсолютный();
					
					Зеленый = РГБЦвет.Зеленый; 
					Красный = РГБЦвет.Красный; 
					Синий = РГБЦвет.Синий;
					
					ХЕКСЦВЕТ = "#" + Сред(DecToAny(ПобитовоеИли(ПобитовоеИли(ПобитовоеИли(Синий, ПобитовыйСдвигВлево(Зеленый, 8)), ПобитовыйСдвигВлево(Красный, 16)), ПобитовыйСдвигВлево(1, 24)), 16), 2);
					СтрокаТега = СтрШаблон("<w:color w:val=""%1""/>", ХЕКСЦВЕТ);	
					ТекстХМЛ = ДобавитьТекст(ТекстХМЛ, СтрокаТега);
					
				КонецЕсли; 
				
				Если ЦветФона <> Новый Цвет() Тогда
					
					РГБЦвет = ЦветФона.ПолучитьАбсолютный();
					
					Зеленый = РГБЦвет.Зеленый; 
					Красный = РГБЦвет.Красный; 
					Синий = РГБЦвет.Синий;
					
					ХЕКСЦВЕТ = "#" + Сред(DecToAny(ПобитовоеИли(ПобитовоеИли(ПобитовоеИли(Синий, ПобитовыйСдвигВлево(Зеленый, 8)), ПобитовыйСдвигВлево(Красный, 16)), ПобитовыйСдвигВлево(1, 24)), 16), 2);
					СтрокаТега = СтрШаблон("<w:shd w:val=""clear"" w:color=""auto"" w:fill=""%1""/>", ХЕКСЦВЕТ);	
					ТекстХМЛ = ДобавитьТекст(ТекстХМЛ, СтрокаТега);
					
				КонецЕсли;
				
				ТекстХМЛ = ДобавитьТекст(ТекстХМЛ, "<w:rFonts w:ascii=""Times New Roman"" w:hAnsi=""Times New Roman"" w:cs=""Times New Roman""/>");	
				
				
				Если Шрифт.Полужирный <> Неопределено И Шрифт.Полужирный Тогда
					ТекстХМЛ = ДобавитьТекст(ТекстХМЛ, "<w:b/>");		
				КонецЕсли;
				
				Если Шрифт.Наклонный <> Неопределено И Шрифт.Наклонный Тогда
					ТекстХМЛ = ДобавитьТекст(ТекстХМЛ, "<w:i/>");		
				КонецЕсли;
				
				Если Шрифт.Подчеркивание <> Неопределено И Шрифт.Подчеркивание Тогда
					ТекстХМЛ = ДобавитьТекст(ТекстХМЛ, "<w:u w:val=""single""/>");		
				КонецЕсли;  
				ТекстХМЛ = ДобавитьТекст(ТекстХМЛ, "</w:rPr>");
				ТекстХМЛ = ДобавитьТекст(ТекстХМЛ, Текст + ЭлементыПараграфа.Текст +ЗакрывающийТег(Текст));     
				
			КонецЕсли;   
			
			Если ТипЗнч(ЭлементыПараграфа) = ТипКартинкаФД Тогда 
				
				СтруктураКартинки = Новый Структура("АдресКартинки");
				НомерКартинки = НомерКартинки + 1;    
				
				Если ТипЗнч(ЭлементыПараграфа.Картинка) = Тип("Картинка") Тогда
					КартинкаДвоичныеДанные = ЭлементыПараграфа.Картинка.ПолучитьДвоичныеДанные();
					
				ИначеЕсли СтрНайти(ЭлементыПараграфа.Картинка, "https://") Тогда
					
					АдресФайла = ЭлементыПараграфа.Картинка;
					Защита = Новый ЗащищенноеСоединениеOpenSSL(Неопределено, Неопределено);
					СтруктураУРИ = ОбщегоНазначенияКлиентСервер.СтруктураURI(АдресФайла);
					Попытка
						Соединение = Новый HTTPСоединение(СтруктураУРИ.ИмяСервера, , , , , , Защита);
					Исключение
						Сообщить(ОписаниеОшибки());
					КонецПопытки;
					Запрос = Новый HTTPЗапрос(СтруктураУРИ.ПутьНаСервере);
					Ответ = ОтправитьЗапрос(Соединение, Запрос);
					Если Ответ.КодСостояния = 200 Тогда
						//Как то обрабатываем результат
						КартинкаДвоичныеДанные = Ответ.ПолучитьТелоКакДвоичныеДанные();
						//АдресХранилища = ПоместитьВоВременноеХранилище(ДД, Новый УникальныйИдентификатор);
					Иначе
						
						КартинкаДвоичныеДанные = ЭлементыПараграфа.Картинка; 
						
				 КонецЕсли;
				 
				Иначе
					
					//Если ЭлементыПараграфа.Высота > 0 И ЭлементыПараграфа.Ширина > 0 Тогда 
					//	Высота = ЭлементыПараграфа.Высота/4;
					//	Ширина = ЭлементыПараграфа.Ширина/4;
					//	//КоэффициентПересчета = 914400/2.54/10*1000	
					//	Если Ширина > 160  Тогда
					//		СтруктураКартинки.Вставить("Ширина", 160);
					//		СтруктураКартинки.Вставить("Высота", Высота/(Ширина/160));	
					//	Иначе
					//		СтруктураКартинки.Вставить("Ширина", Ширина);
					//		СтруктураКартинки.Вставить("Высота", Высота);
					//	КонецЕсли;
					//КонецЕсли;
					СтрокаКартинка = ЭлементыПараграфа.Картинка;
					СтрокаКартинка = СтрЗаменить(СтрокаКартинка, "data:image/png;base64,", "");	
					КартинкаДвоичныеДанные = Base64Значение(СтрокаКартинка);
				КонецЕсли;
				
				ТегКартинки = СтрШаблон("{v8 КартинкаФД_%1_Файл}", НомерКартинки);   
				КлючСтроки = СтрШаблон("КартинкаФД_%1_Файл", НомерКартинки); 
				ТекстХМЛ = ДобавитьТекст(ТекстХМЛ, Текст + ТегКартинки +ЗакрывающийТег(Текст));
				СтруктураКартинки.АдресКартинки = ПоместитьВоВременноеХранилище(КартинкаДвоичныеДанные);    
				
				ДанныеОбъекта.Вставить(КлючСтроки, СтруктураКартинки);
			КонецЕсли;
			
			ТекстХМЛ = ДобавитьТекст(ТекстХМЛ, ЗакрывающийТег(ЗапускТекста));
			
		КонецЦикла; 
		ТекстХМЛ = ДобавитьТекст(ТекстХМЛ, "</w:p>"); 
		
	КонецЦикла;    
	
	ТекстОбласти = СтрЗаменить(ТекстОбласти, ТекстЗамены, ТекстХМЛ); 

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

Функция ЗакрывающийТег(Тег)
	
	Возврат СтрЗаменить(Тег, "<w", "</w") 	
	
КонецФункции // ()

Функция ДобавитьТекст(ТекстХМЛ, ДополнительныеДанные)
	
	Возврат ТекстХМЛ + ДополнительныеДанные; 	
	
КонецФункции // ()

Функция DecToAny(Знач тЗначение, тОснование)
	
	тРезультат = "";
	
	Пока тЗначение > 0 Цикл
		тРезультат = Сред("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", тЗначение%тОснование + 1, 1) + тРезультат;
		тЗначение = Цел(тЗначение/тОснование) ;
	КонецЦикла;
	
	Возврат тРезультат;
	
КонецФункции            

Функция ОтправитьЗапрос(Соединение, Запрос)
	Ответ = Соединение.ВызватьHTTPМетод("GET", Запрос);
	Если Ответ.КодСостояния = 200 Тогда
        //Выходим из рекурсии
		Возврат Ответ;
	ИначеЕсли Ответ.КодСостояния > 300 И Ответ.КодСостояния < 400 Тогда
		//Редирект
		Ответ = ОбработатьРедирект(Соединение, Ответ);
	ИначеЕсли Ответ.КодСостояния >= 400 Тогда
		//Обработка ошибки
		Возврат Ответ;
	КонецЕсли;
	Возврат Ответ;
КонецФункции               

Функция ОбработатьРедирект(Соединение, Ответ)

В самом макете у меня добавлено два списка, это необходимо, чтобы у макета сформировались к ним описания в xml и в коде можно было бы применить форматирование списков.

Чтобы узнать, какой код необходим, надо разархивировать макет в формате docx, тогда в появившейся папке находим файл numbering.xml и оттуда берем необходимые параметры.

У меня получилось так:

 

 

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

Использовала следующие статьи и обработки на Инфостарте:

//infostart.ru/1c/tools/860960/

//infostart.ru/1c/tools/1324110/

//infostart.ru/1c/articles/1915944/

Тестировалось на "Библиотека стандартных подсистем", редакция 3.1 (3.1.9.104).

Проверено на следующих конфигурациях и релизах:

  • 1С:ERP Управление предприятием 2, релизы 2.5.14.74

Форматированный документ WORD Office open XML БСП

См. также

Infostart Toolkit: Инструменты разработчика 1С 8.3 на управляемых формах

Инструментарий разработчика Роли и права Запросы СКД Платформа 1С v8.3 Управляемые формы Запросы Система компоновки данных Конфигурации 1cv8 Платные (руб)

Набор инструментов программиста и специалиста 1С для всех конфигураций на управляемых формах. В состав входят инструменты: Консоль запросов, Консоль СКД, Консоль кода, Редактор объекта, Анализ прав доступа, Метаданные, Поиск ссылок, Сравнение объектов, Все функции, Подписки на события и др. Редактор запросов и кода с раскраской и контекстной подсказкой. Доработанный конструктор запросов тонкого клиента. Продукт хорошо оптимизирован и обладает самым широким функционалом среди всех инструментов, представленных на рынке.

10000 руб.

02.09.2020    127325    688    389    

740

Infostart PrintWizard - создание и редактирование печатных форм в 1С 8.3

Пакетная печать Печатные формы Инструментарий разработчика Платформа 1С v8.3 Запросы 1С:Зарплата и кадры бюджетного учреждения 1С:Конвертация данных 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 Платные (руб)

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

18000 руб.

06.10.2023    8452    25    6    

46

Infostart УДиФ: Управление данными и формами 1С

Инструменты администратора БД Инструментарий разработчика Роли и права Платформа 1С v8.3 Конфигурации 1cv8 Россия Платные (руб)

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

10000 руб.

10.11.2023    4771    12    2    

38

SALE! %

PowerTools

Инструментарий разработчика Инструменты администратора БД Платформа 1С v8.3 Управляемые формы Конфигурации 1cv8 Россия Платные (руб)

Универсальный инструмент программиста для администрирования конфигураций. Сборник наиболее часто используемых обработок под единым интерфейсом.

3600 2280 руб.

14.01.2013    178979    1086    0    

863

Бустер Конвертации данных 3 (Infostart Toolkit)

Инструментарий разработчика 8.3.14 1С:Конвертация данных Россия Платные (руб)

Расширение для конфигурации “Конвертация данных 3”. Добавляет подсветку синтаксиса, детальную контекстную подсказку, глобальный поиск по коду.

15000 руб.

07.10.2021    15132    3    12    

38

Многопоточность. Универсальный «Менеджер потоков» 2.1

Инструментарий разработчика Платформа 1С v8.3 Конфигурации 1cv8 Россия Платные (руб)

Восстановление партий или взаиморасчетов, расчет зарплаты, пакетное формирование документов или отчетов - теперь все это стало доступнее. * Есть желание повысить скорость работы медленных алгоритмов! Но... * Нет времени думать о реализации многопоточности? * о запуске и остановке потоков? * о поддержании потоков в рабочем состоянии? * о передаче данных в потоки и как получить ответ из потока? * об организации последовательности? Тогда ЭТО - то что надо!!!

5000 руб.

07.02.2018    100005    239    97    

298

1С HTML Шаблоны / HTML Templates

Инструментарий разработчика Платформа 1С v8.3 Конфигурации 1cv8 Платные (руб)

Быстрая и удобная обработка для работы с шаблонами HTML. Позволяет легко и быстро формировать код HTML.

2040 руб.

27.12.2017    28443    4    10    

16

[ЕХТ] Фреймворк для Расширений 1С

Инструментарий разработчика Платформа 1С v8.3 Управляемые формы Платные (руб)

"Фреймворк для Расширений 1С" это универсальное и многофункциональное решение, упрощающее разработку и поддержку создаваемых Расширений. Поставляется в виде комплекта из нескольких Расширений с открытым исходным кодом. Работает в любых Конфигурациях в режиме Управляемого приложения с режимом совместимости 8.3.12 и выше без необходимости внесения изменений в Конфигурацию.

3000 руб.

27.08.2019    18539    6    8    

40
Оставьте свое сообщение