Всем привет! Собственно вопрос такой: в конфигурациях Документооборот есть процедура ВыполнитьЗаменуПолейИСтрокВДокументеMSOfficeOpenXML которая выполняет автозаполнение документов docx. Там реализовано автозаполнение только одной табличной части товары в docx, кто-нибудь занимался доработкой этой процедуры, чтобы можно было заполнять несколько табличных частей? Пока у меня есть решение, но в нем все работает когда только одинаковое количество строк в нескольких табличных частей. Когда разное количество, выходит ошибка порядка записи XML. Вот мое решение, комментариями //Доработка выделил что доработано мной. Также изменен массив структур МассивДанныхДляАвтоЗамен, там теперь есть свойство НомерТаблицы:
Если кто-то занимался подобным или есть информация по данной теме, буду признателен.
Процедура ВыполнитьЗаменуПолейИСтрокВДокументеMSOfficeOpenXML(
ЧтениеXML, ЗаписьXML, АдресXML, МассивДанныхДляАвтоЗамен, ЗаполнятьТолькоПоляРегистрации = Ложь)
// Примечание. В файле шаблона не должно быть скрытых закладок. И закладки не должны друг друга перекрывать, т.е.
// внутри действия одной закладки не должно быть других закладок.
// И скрытые закладки не нужны, это отражено в документации.
// Получаем количество строк в таблице товары, если она заполнена.
КоличествоСтрок = 0;
// Доработка(
ИспользуетсяНомерТаблицы = Ложь;
НомерТаблицыЗаполнения = 0;
// )Доработка
Для Каждого Настройка Из МассивДанныхДляАвтоЗамен Цикл
Если Настройка.НомерКолонкиТабличнойЧасти = 1 Тогда
КоличествоСтрок = Настройка.ЗначениеЗамены.Количество();
// Доработка(
ИспользуетсяНомерТаблицы = Настройка.Свойство("НомерТаблицы");
// )Доработка
Прервать;
КонецЕсли;
КонецЦикла;
ЧтениеXML.ИгнорироватьПробелы = Ложь;
ФлагНайденоПоле = Ложь;
// Закрывающий тэг bookMarkEnd должен быть с таким же id, каи открывающий
// (например <w:bookmarkEnd w:id="6"/>):
IdТегаBookmark = Неопределено;
ФлагНайденаСтрока = Ложь;
ПереводСтроки = Ложь; ВозможенПереводСтроки = Ложь;
СтрЗамены = "";
СтрПоиска = "";
СтрокаТаблицы = 0; НомерКолонки = 0;
ФлагНайденаТаблица = Ложь; ФлагНайденаНашаТаблица = Ложь;
ФлагНайденаСтрокаТаблицы = Ложь;
// Иногда бывает, что текст поля "разрезает на куски" теги проверки орфографии, т.е. часть текста имеет по мнению Word ошибку,
// тексты внутри таких тегов надо заменять на пустую строку.
// но только уже после удачной замены, т.к. обычный текст тоже может быть внутри тегов орфограции - он должен остаться.
ФлагПолеУдачноЗаменено = Ложь;
ПервыйТег = КоличествоСтрок > 1; ПропуститьСтроку = Ложь;
СтрокаXMLОткрыт = Ложь;
Пока ЧтениеXML.Прочитать() Цикл
Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
// Найдено предполагаемое поле для замены
ФлагТекущийТэгBookmarkStart = Ложь;
Если ЧтениеXML.Имя = "w:bookmarkStart" Тогда
ФлагНайденоПоле = Истина;
СкрытаяЗакладка = Ложь;
ФлагПолеУдачноЗаменено = Ложь;
ФлагТекущийТэгBookmarkStart = Истина;
КонецЕсли;
Если ЧтениеXML.Имя = "w:t" Тогда
ФлагНайденаСтрока = Истина;
КонецЕсли;
// Предполагаем, что найдена наша таблица для замены
Если ЧтениеXML.Имя = "w:tbl" И КоличествоСтрок > 0 Тогда
ФлагНайденаТаблица = Истина;
СтрокаТаблицы = 0;
КонецЕсли;
// Предполагаем, что найдена строка нашей таблица для замены
Если ЧтениеXML.Имя = "w:tr" И ФлагНайденаТаблица Тогда
Если СтрокаТаблицы > КоличествоСтрок И ФлагНайденаНашаТаблица Тогда
ПропуститьСтроку = Истина;
Продолжить;
КонецЕсли;
СтрокаТаблицы = СтрокаТаблицы + 1;
Если СтрокаТаблицы = 2 И КоличествоСтрок > 1 Тогда
ФлагНайденаСтрокаТаблицы = Истина;
КонецЕсли;
КонецЕсли;
Если ЧтениеXML.Имя = "w:tc" Тогда
НомерКолонки = НомерКолонки + 1;
КонецЕсли;
// В случае перезаполнения файла, этот тег пропускаем, чтобы не создавались лишние переводы строки.
Если ЧтениеXML.Имя = "w:br" И ВозможенПереводСтроки И Не ЗаполнятьТолькоПоляРегистрации Тогда
ПереводСтроки = Истина;
Продолжить;
КонецЕсли;
Если ПропуститьСтроку Тогда
Продолжить;
КонецЕсли;
ЗаписьXML.ЗаписатьНачалоЭлемента(ЧтениеXML.Имя);
Если ПервыйТег Или ФлагНайденаСтрокаТаблицы Тогда
Если Не СтрокаXMLОткрыт Тогда
КопияСтрокиXML = СоздатьНовуюЗапись(АдресXML);
СтрокаXMLОткрыт = Истина;
КонецЕсли;
КопияСтрокиXML.ЗаписатьНачалоЭлемента(ЧтениеXML.Имя);
КонецЕсли;
// Читаем и записываем атрибуты тега
Если ЧтениеXML.КоличествоАтрибутов() > 0 Тогда
Пока ЧтениеXML.ПрочитатьАтрибут() Цикл
Если ФлагНайденоПоле И ЧтениеXML.Имя = "w:name"
И Найти(ЧтениеXML.Значение, "_GoBack") = 0 Тогда
СтрПоиска = ЧтениеXML.Значение;
// Скрытые закладки начинаются с символа "_"
Если Лев(ЧтениеXML.Значение, 1) = "_" Тогда
СкрытаяЗакладка = Истина;
КонецЕсли;
Если ФлагНайденаТаблица И Не ФлагНайденаНашаТаблица Тогда
Для Каждого НастройкаЗамены Из МассивДанныхДляАвтоЗамен Цикл
Если НастройкаЗамены.ТермДляЗамены = СтрПоиска
И НастройкаЗамены.НомерКолонкиТабличнойЧасти > 0 Тогда
ФлагНайденаНашаТаблица = Истина;
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;
// Доработка(
Если ФлагНайденаТаблица И ИспользуетсяНомерТаблицы Тогда
Для Каждого НастройкаЗамены Из МассивДанныхДляАвтоЗамен Цикл
Если НастройкаЗамены.ТермДляЗамены = СтрПоиска
И НастройкаЗамены.НомерКолонкиТабличнойЧасти > 0
И НастройкаЗамены.НомерТаблицы <> НомерТаблицыЗаполнения
Тогда
НомерТаблицыЗаполнения = НастройкаЗамены.НомерТаблицы;
КоличествоСтрок = НастройкаЗамены.ЗначениеЗамены.Количество();
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;
// )Доработка
Если ПервыйТег Или ФлагНайденаСтрокаТаблицы Тогда
КопияСтрокиXML.ЗаписатьАтрибут(ЧтениеXML.Имя, Лев(СтрПоиска, 19) + "1");
КонецЕсли;
ИначеЕсли ПервыйТег Или ФлагНайденаСтрокаТаблицы Тогда
КопияСтрокиXML.ЗаписатьАтрибут(ЧтениеXML.Имя, ЧтениеXML.Значение);
КонецЕсли;
ЗаписьXML.ЗаписатьАтрибут(ЧтениеXML.Имя, ЧтениеXML.Значение);
// Доработка Изменение из патча EF_ОШ26431(
//Если ФлагНайденоПоле И Найти(ЧтениеXML.Значение, "_GoBack") > 0 Тогда
// ФлагНайденоПоле = Ложь; // Весь тег внутри этого поля перезапишем "как есть".
// СтрЗамены = "";
//КонецЕсли;
// )Доработка Изменение из патча EF_ОШ26431
Если ФлагТекущийТэгBookmarkStart И ЧтениеXML.Имя = "w:id" И IdТегаBookmark = Неопределено Тогда
IdТегаBookmark = ЧтениеXML.Значение;
КонецЕсли;
КонецЦикла
КонецЕсли;
ПервыйТег = Ложь;
// Текст тега
ИначеЕсли ЧтениеXML.ТипУзла = ТипУзлаXML.Текст Тогда
Если ФлагПолеУдачноЗаменено Тогда
// После удачной замены, все остальные куски текста до конца поля нужно пропустить,
// иногда текст режется на куски тегами проверки орфографии.
Продолжить;
ИначеЕсли ПереводСтроки И ВозможенПереводСтроки И Не ЗаполнятьТолькоПоляРегистрации Тогда
ЗаписьXML.ЗаписатьБезОбработки("");
// Перезаполняем поля таблицы
ИначеЕсли ФлагНайденаНашаТаблица И ФлагНайденоПоле И ФлагНайденаСтрока Тогда
Если ПропуститьСтроку Тогда
Продолжить;
КонецЕсли;
СтрЗамены = СтрПоиска; // Имя поля, найденного ранее
БылаВыполненаЗамена = Ложь;
Если ЗначениеЗаполнено(СтрЗамены) Тогда
// Доработка(
Если ИспользуетсяНомерТаблицы Тогда
Для Каждого НастройкаЗамены Из МассивДанныхДляАвтоЗамен Цикл
Если НастройкаЗамены.НомерТаблицы = НомерТаблицыЗаполнения Тогда
ИмяРеквизита = СтрЗаменить(Лев(НастройкаЗамены.ТермДляЗамены, 20), " ", "_");
Если ИмяРеквизита <> СтрПоиска Тогда
Продолжить;
КонецЕсли;
СтрЗамены = НастройкаЗамены.ЗначениеЗамены[СтрокаТаблицы - 2].Значение;
БылаВыполненаЗамена = Истина;
Прервать;
КонецЕсли;
КонецЦикла;
Иначе
// )Доработка
Для Каждого НастройкаЗамены Из МассивДанныхДляАвтоЗамен Цикл
ИмяРеквизита = СтрЗаменить(Лев(НастройкаЗамены.ТермДляЗамены, 20), " ", "_");
Если ИмяРеквизита <> СтрПоиска Тогда
Продолжить;
КонецЕсли;
СтрЗамены = НастройкаЗамены.ЗначениеЗамены[СтрокаТаблицы - 2].Значение;
БылаВыполненаЗамена = Истина;
Прервать;
КонецЦикла;
// Доработка(
КонецЕсли;
// )Доработка
КонецЕсли;
ЗаписатьВXMLСодержимое(ЗаписьXML, СтрЗамены);
Если ФлагНайденаСтрокаТаблицы Тогда
ЗаписатьВXMLСодержимое(КопияСтрокиXML, СтрЗамены);
КонецЕсли;
СтрЗамены = "";
ФлагНайденоПоле = Ложь;
// Перезаполняем поля документа. Замена поля на строку по шаблону.
ИначеЕсли ФлагНайденоПоле И ФлагНайденаСтрока Тогда
Для Каждого НастройкаЗамены Из МассивДанныхДляАвтоЗамен Цикл
ИмяРеквизита = СтрЗаменить(Лев(НастройкаЗамены.ТермДляЗамены, 20), " ", "_");
Если ИмяРеквизита = СтрПоиска И НастройкаЗамены.НомерКолонкиТабличнойЧасти = 0 Тогда
СтрЗамены = НастройкаЗамены.ЗначениеЗамены;
Прервать;
КонецЕсли;
КонецЦикла;
Если ЗначениеЗаполнено(СтрЗамены) Тогда
ЗаписатьВXMLСодержимое(ЗаписьXML, СтрЗамены);
// Теперь все теги после удачной замены до конца тега: <w:bookmarkEnd w:id="Число"/> с таким же id,
// как перед этим bookmarkStart: <w:bookmarkStart w:id="Число" w:name="ИмяПоляАвтозамены"/>
ФлагПолеУдачноЗаменено = Истина;
ИначеЕсли Не СкрытаяЗакладка И Не ЗаполнятьТолькоПоляРегистрации И СтрЗамены <> ЧтениеXML.Значение Тогда
ЗаписьXML.ЗаписатьТекст(Символ(160));
Иначе
ЗаписьXML.ЗаписатьТекст(ЧтениеXML.Значение);
КонецЕсли;
ФлагНайденоПоле = Ложь;
СтрЗамены = "";
ВозможенПереводСтроки = Истина;
// Перезаполняем строки документа. Замена строки шаблона на строку (один раз).
ИначеЕсли ФлагНайденаСтрока Тогда
СтрЗамены = ЧтениеXML.Значение;
БылаВыполненаЗамена = Ложь;
Для Каждого НастройкаЗамены Из МассивДанныхДляАвтоЗамен Цикл
Если Не ЗначениеЗаполнено(НастройкаЗамены.ЗаменяемаяСтрока) Тогда
Продолжить;
КонецЕсли;
Если Найти(СтрЗамены, НастройкаЗамены.ЗаменяемаяСтрока) > 0 Тогда
СтрЗамены = СтрЗаменить(СтрЗамены, НастройкаЗамены.ЗаменяемаяСтрока,
НастройкаЗамены.ЗначениеЗамены);
БылаВыполненаЗамена = Истина;
КонецЕсли;
КонецЦикла;
ЗаписатьВXMLСодержимое(ЗаписьXML, СтрЗамены);
Если ФлагНайденаСтрокаТаблицы Тогда
ЗаписатьВXMLСодержимое(КопияСтрокиXML, СтрЗамены);
КонецЕсли;
Иначе
ЗаписьXML.ЗаписатьТекст(ЧтениеXML.Значение);
Если ФлагНайденаСтрокаТаблицы Тогда
КопияСтрокиXML.ЗаписатьТекст(ЧтениеXML.Значение);
КонецЕсли;
КонецЕсли;
// Читаем и записываем конец тега
ИначеЕсли ЧтениеXML.ТипУзла = ТипУзлаXML.КонецЭлемента Тогда
// В случае перезаполнения файла, этот тег пропускаем, чтобы не создавались лишние переводы строки.
Если ЧтениеXML.Имя = "w:br" И ВозможенПереводСтроки И Не ЗаполнятьТолькоПоляРегистрации Тогда
Продолжить;
КонецЕсли;
Если ФлагНайденаТаблица И ЧтениеXML.Имя = "w:tbl" Тогда
ФлагНайденаТаблица = Ложь;
ФлагНайденаНашаТаблица = Ложь;
ПропуститьСтроку = Ложь;
СтрЗамены = "";
КонецЕсли;
Если ПропуститьСтроку Тогда
Продолжить;
КонецЕсли;
ЗаписьXML.ЗаписатьКонецЭлемента();
Если ФлагНайденаСтрокаТаблицы Тогда
КопияСтрокиXML.ЗаписатьКонецЭлемента();
КонецЕсли;
ЭтоBookmarkEnd = Ложь;
Если ЧтениеXML.Имя = "w:bookmarkEnd" Тогда
ЭтоBookmarkEnd = Истина; // в самом конце, после проверок таблицы нужно сбросить признаки перевода строки.
ЭтоКонецПоляСТемЖеId = Ложь;
Если ЧтениеXML.КоличествоАтрибутов() > 0 Тогда
Пока ЧтениеXML.ПрочитатьАтрибут() Цикл
Если ЧтениеXML.Имя = "w:id" И ЧтениеXML.Значение = IdТегаBookmark Тогда
ЭтоКонецПоляСТемЖеId = Истина;
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;
Если ЭтоКонецПоляСТемЖеId Тогда
IdТегаBookmark = Неопределено;
ФлагНайденоПоле = Ложь; СкрытаяЗакладка = Ложь;
СтрЗамены = "";
ФлагПолеУдачноЗаменено = Ложь;
КонецЕсли;
КонецЕсли;
Если ФлагНайденаСтрока Тогда
ФлагНайденаСтрока = Ложь;
СтрЗамены = "";
КонецЕсли;
Если ЧтениеXML.Имя = "w:tr" И ФлагНайденаТаблица Тогда
НомерКолонки = 0;
ФлагНайденаСтрокаТаблицы = Ложь;
Если СтрокаТаблицы = 2 И КоличествоСтрок > 1 Тогда
КопияСтрокиXML.ЗаписатьКонецЭлемента();
КопияСтрокиXML.Закрыть();
СтрокаXMLОткрыт = Ложь;
ЗаменитьПространствоИменR(АдресXML);
// Добавление в документ копии первой строки таблицы, с последующим заполнением данными документа
Если ФлагНайденаНашаТаблица Тогда
Пока СтрокаТаблицы - 1 < КоличествоСтрок Цикл
ЧтениеСтрокиXML = Новый ЧтениеXML();
ЧтениеСтрокиXML.ОткрытьФайл(АдресXML);
ЧтениеСтрокиXML.ИгнорироватьПробелы = Ложь;
ФлагНайденоПоле = Ложь; ФлагНайденаСтрока = Ложь;
Пока ЧтениеСтрокиXML.Прочитать() Цикл
Если ЧтениеСтрокиXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
// Первый тег пропускаем
Если ЧтениеСтрокиXML.Имя = "w:document" Тогда
Продолжить;
КонецЕсли;
Если ЧтениеСтрокиXML.Имя = "w:bookmarkStart" Тогда
ФлагНайденоПоле = Истина;
КонецЕсли;
Если ЧтениеСтрокиXML.Имя = "w:t" Тогда
ФлагНайденаСтрока = Истина;
КонецЕсли;
Если ЧтениеСтрокиXML.Имя = "w:tr" Тогда
СтрокаТаблицы = СтрокаТаблицы + 1;
КонецЕсли;
Если ЧтениеСтрокиXML.Имя = "w:tc" Тогда
НомерКолонки = НомерКолонки + 1;
КонецЕсли;
// В случае перезаполнения файла, этот тег пропускаем, чтобы не создавались лишние переводы строки.
Если ЧтениеСтрокиXML.Имя = "w:br" И ВозможенПереводСтроки
И Не ЗаполнятьТолькоПоляРегистрации Тогда
ПереводСтроки = Истина;
Продолжить;
КонецЕсли;
ЗаписьXML.ЗаписатьНачалоЭлемента(ЧтениеСтрокиXML.Имя);
Если ЧтениеСтрокиXML.КоличествоАтрибутов() > 0 Тогда
Пока ЧтениеСтрокиXML.ПрочитатьАтрибут() Цикл
Если ФлагНайденоПоле И ЧтениеСтрокиXML.Имя = "w:name"
И Найти(ЧтениеXML.Значение, "_GoBack") = 0 Тогда
СтрПоиска = ЧтениеСтрокиXML.Значение;
КонецЕсли;
ЗаписьXML.ЗаписатьАтрибут(ЧтениеСтрокиXML.Имя, ЧтениеСтрокиXML.Значение);
КонецЦикла
КонецЕсли;
ИначеЕсли ЧтениеСтрокиXML.ТипУзла = ТипУзлаXML.Текст Тогда
Если ПереводСтроки И ВозможенПереводСтроки И Не ЗаполнятьТолькоПоляРегистрации Тогда
ЗаписьXML.ЗаписатьБезОбработки("");
ИначеЕсли ФлагНайденоПоле И ФлагНайденаСтрока Тогда
СтрЗамены = ЧтениеСтрокиXML.Значение;
БылаВыполненаЗамена = Ложь;
// Доработка(
Если ИспользуетсяНомерТаблицы Тогда
Для Каждого НастройкаЗамены Из МассивДанныхДляАвтоЗамен Цикл
Если НастройкаЗамены.НомерТаблицы = НомерТаблицыЗаполнения Тогда
ИмяРеквизита = Лев(НастройкаЗамены.ТермДляЗамены, 19) + "1";
Если ИмяРеквизита <> СтрПоиска Тогда
Продолжить;
КонецЕсли;
СтрЗамены = НастройкаЗамены.ЗначениеЗамены[СтрокаТаблицы - 2].Значение;
БылаВыполненаЗамена = Истина;
Прервать;
КонецЕсли;
КонецЦикла;
Иначе
// )Доработка
Для Каждого НастройкаЗамены Из МассивДанныхДляАвтоЗамен Цикл
ИмяРеквизита = Лев(НастройкаЗамены.ТермДляЗамены, 19) + "1";
Если ИмяРеквизита <> СтрПоиска Тогда
Продолжить;
КонецЕсли;
СтрЗамены = НастройкаЗамены.ЗначениеЗамены[СтрокаТаблицы - 2].Значение;
БылаВыполненаЗамена = Истина;
Прервать;
КонецЦикла;
// Доработка(
КонецЕсли;
// )Доработка
ЗаписатьВXMLСодержимое(ЗаписьXML, СтрЗамены);
СтрЗамены = "";
ФлагНайденоПоле = Ложь;
Иначе
ЗаписьXML.ЗаписатьТекст(ЧтениеСтрокиXML.Значение);
КонецЕсли;
ИначеЕсли ЧтениеСтрокиXML.ТипУзла = ТипУзлаXML.КонецЭлемента Тогда
// В случае перезаполнения файла, этот тег пропускаем, чтобы не создавались лишние переводы строки.
Если ЧтениеСтрокиXML.Имя = "w:br" И ВозможенПереводСтроки
И Не ЗаполнятьТолькоПоляРегистрации Тогда
Продолжить;
КонецЕсли;
Если ЧтениеСтрокиXML.Имя = "w:document" Тогда
Продолжить;
КонецЕсли;
ЗаписьXML.ЗаписатьКонецЭлемента();
Если ФлагНайденоПоле И ЧтениеСтрокиXML.Имя = "w:bookmarkEnd" Тогда
ФлагНайденоПоле = Ложь;
СтрЗамены = "";
КонецЕсли;
Если ФлагНайденаСтрока Тогда
ФлагНайденаСтрока = Ложь;
СтрЗамены = "";
КонецЕсли;
Если ЧтениеСтрокиXML.Имя = "w:tr" Тогда
НомерКолонки = 0;
КонецЕсли;
КонецЕсли;
КонецЦикла;
ЧтениеСтрокиXML.Закрыть();
КонецЦикла;
КонецЕсли;
КонецЕсли;
КонецЕсли;
Если ЭтоBookmarkEnd И ВозможенПереводСтроки Тогда
ПереводСтроки = Ложь;
ВозможенПереводСтроки = Ложь;
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
ПоказатьЕсли кто-то занимался подобным или есть информация по данной теме, буду признателен.
Свернуть все
Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот