Как удалить пустую строку из макета Word (DOCX) без использования COM-объекта?

Программист 1С v8.3 (Управляемые формы) 1С:Зарплата и Управление Персоналом IT и автоматизация бизнеса
← На главную

При формировании печатных форм на базе шаблонов Microsoft Word (DOCX) в программах 1С часто возникает ситуация, когда часть параметров является опциональной. Если параметр вынесен на отдельную строку макета в виде {v8 Параметр}, а в коде ему присваивается пустое значение, в итоговом документе часто остается пустой абзац с отступами, нарушающий визуальную структуру текста. Разберем причины такого поведения платформы и механизмов БСП, а также рассмотрим надежные способы решения этой проблемы без использования COM-соединений, что особенно актуально для серверов под управлением Linux.

Почему возникает пустая строка при незаполненном параметре

Проанализируем внутреннее устройство документа DOCX (Office Open XML). Файл формата .docx представляет собой обычный ZIP-архив, содержащий набор XML-файлов. Текстовое содержимое документа хранится в файле word/document.xml, где текст разбит на узлы абзацев <w:p>, внутри которых находятся блоки форматирования и строки <w:r><w:t>...</w:t></w:r>.

Штатная подсистема печати БСП производит замену маркеров вида {v8 Параметр} исключительно на уровне содержимого тега <w:t>. Если в макете тег располагается на отдельной строке, то в XML-структуре ему соответствует полноценный узел абзаца. При подстановке пустой строки узел <w:p> никуда не исчезает: в результирующем документе сохраняется пустой абзац со всеми стилями, межстрочными интервалами и отступами. Специального управляющего символа, передача которого заставила бы БСП автоматически удалить родительский абзац, в платформе не предусмотрено.

Рассмотрим рабочие варианты обхода и устранения этой проблемы.

Способ 1. Использование механизма областей макета БСП (рекомендуемый)

Наиболее правильный и штатный способ управления опциональными абзацами в БСП — это разбиение документа на секции при помощи именованных областей. Механизм БСП поддерживает теги областей в формате {v8 Область.ИмяОбласти} и {/v8 Область.ИмяОбласти}.

Разберем по шагам реализацию этого подхода:

  1. В макете DOCX заключаем необязательный пункт или абзац целиком в теги области. Открывающий тег помещается в начале строки, а закрывающий — в конце абзаца, включая символ перевода строки:
    {v8 Область.ДополнительныйПункт}5.2. Работнику предоставляется {v8 ОписаниеОтпуска}.{/v8 Область.ДополнительныйПункт}
  2. В программном коде формируем документ последовательным выводом необходимых областей с помощью методов УправлениеПечатью:

// Проверяем наличие данных перед выводом блока
Если ЗначениеЗаполнено(ТекстДополнительногоОтпуска) Тогда
    ОбластьБлока = УправлениеПечатью.ОбластьМакета(Макет, ОписаниеОбластей.ДополнительныйПункт);
    
    ПараметрыБлока = Новый Структура;
    ПараметрыБлока.Вставить("ОписаниеОтпуска", ТекстДополнительногоОтпуска);
    
    УправлениеПечатью.ПрисоединитьОбластьИЗаполнитьПараметры(ПечатнаяФорма, ОбластьБлока, ПараметрыБлока);
КонецЕсли;

Если условие не выполняется, область просто не присоединяется к результирующему документу. В этом случае узел абзаца вообще не попадает в итоговый XML-файл, и разрыв текста полностью отсутствует.

Способ 2. Перенос разрыва строки внутрь значения параметра

Если документ формируется целиком за один вызов без секционирования на области, можно применить форматирование строки внутри кода 1С.

Посмотрим на пример организации шаблона:

  1. В макете Word убираем перевод строки перед параметром. Ставим маркер {v8 ДополнительныйПункт} вплотную к предыдущему тексту или в конце предшествующего абзаца.
  2. В коде 1С добавляем символ перевода строки Символы.ПС непосредственно к значению, если оно заполнено:

Если ЗначениеЗаполнено(ДополнительныйОтпуск) Тогда
    // Формируем текст пункта с переводом строки в начале
    ПараметрыДокумента.Вставить("ДополнительныйПункт", Символы.ПС + "5.2. Работнику предоставляется " + СокрЛП(ДополнительныйОтпуск));
Иначе
    // Если данных нет, передаем пустую строку без переноса
    ПараметрыДокумента.Вставить("ДополнительныйПункт", "");
КонецЕсли;

Когда условие не выполняется, пустая строка подставляется в конец существующего абзаца, не создавая нового переноса и лишних отступов.

Способ 3. Прямая постобработка файла DOCX средствами работы с ZIP и XML

Если изменить структуру макета невозможно, применим низкоуровневую обработку полученного файла. Поскольку DOCX является ZIP-архивом, платформа 1С позволяет распаковать его, скорректировать XML и упаковать обратно без COM и внешних библиотек.

Разберем по шагам последовательность действий:

  1. Распаковываем сформированный двоичный файл во временный каталог с помощью объекта ЧтениеZipФайла.
  2. Считываем файл word/document.xml в текстовую переменную или обрабатываем его через ЧтениеXML / ФабрикаXDTO.
  3. Удаляем пустые узлы абзацев вида <w:p><w:r><w:t></w:t></w:r></w:p> или узлы <w:p/>, в которых нет текстового содержимого.
  4. Записываем измененный файл word/document.xml обратно.
  5. Упаковываем каталог в новый файл DOCX с помощью объекта ЗаписьZipФайла.

Этот способ требует аккуратности при работе со структурой XML, однако обеспечивает полную независимость от операционной системы и корректно работает на серверах под управлением Windows и Linux.

← На главную