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

08.02.24

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

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

Скачать файл

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование По подписке [?] Купить один файл
Вывод форматированного документа в формате Office open XML (WORD) через сервер с использованием БСП.:
.epf 24,13Kb
5
5 Скачать (1 SM) Купить за 1 850 руб.

В макете ворда делаем определенный тег для форматированного документа, у меня это  {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 БСП

См. также

SALE! 15%

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

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

10000 руб.

02.09.2020    160233    882    399    

866

SALE! 15%

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

Инструмент представляет собой обработку для проведения свёртки или обрезки баз данных. Работает на ЛЮБЫХ конфигурациях (УТ, БП, ERP и т.д.). Поддерживаются управляемые и обычные формы. Может выполнять свертку сразу нескольких баз данных и выполнять их автоматически без непосредственного участия пользователя.

8400 7140 руб.

20.08.2024    8087    60    28    

70

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

Инструмент для написания и отладки кода в режиме «1С:Предприятие». Представляет собой консоль кода с возможностью пошаговой отладки, просмотра значений переменных любых типов, использования процедур и функций, просмотра стека вызовов, вычисления произвольных выражений на встроенном языке в контексте точки останова, синтаксического контроля и остановки по ошибке. В консоли используется удобный редактор кода с подсветкой, контекстной подсказкой, возможностью вызова конструкторов запроса и форматной строки.

9360 руб.

17.05.2024    23635    69    45    

117

SALE! 15%

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

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

22200 19980 руб.

06.10.2023    15507    36    7    

71

SALE! 15%

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

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

10000 8500 руб.

10.11.2023    10540    37    27    

62

SALE! 35%

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

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

4800 3120 руб.

14.01.2013    188200    1141    0    

912

SALE! 15%

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

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

15000 12750 руб.

07.10.2021    17367    6    32    

42

Инструментарий разработчика Программист Платные (руб)

Менеджер конфигураций 1С — альтернативный стартер информационных баз 1С:Предприятие.

1800 руб.

21.02.2023    7761    8    35    

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