Почему не работает горизонтальный разделитель страниц при сохранении табличного документа 1С в Word и как настроить перенос?

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

При формировании печатных форм в 1С часто возникает задача сформировать объемный документ с жестким постраничным разбиением: вывести блок строк, проверить помещаемость на листе, при необходимости зафиксировать промежуточные итоги (тоталы) и перенести следующий блок на новую страницу. Разработчики привыкли решать эту задачу связкой методов ПроверитьВывод() и ВывестиГоризонтальныйРазделительСтраниц(). Однако при попытке сохранить полученный ТабличныйДокумент в формат Microsoft Word (DOCX) все заданные разрывы страниц пропадают, а весь текст объединяется в сплошную простыню. Разберем по шагам, почему это происходит и какими способами можно добиться корректного разделения листов в Word.

Выясним причину поведения платформы 1С

Для понимания корня проблемы проанализируем механизм конвертации табличного документа в форматы сторонних офисных пакетов:

  1. Метод ТабДок.ВывестиГоризонтальныйРазделительСтраниц() и свойство области КонецСтраницы разработаны исключительно для встроенного механизма рендеринга 1С — вывода на печать, просмотра внутри платформы и сохранения в форматы MXL или PDF.
  2. При выгрузке в файл DOCX через интерактивное меню «Файл — Сохранить копию» или вызовом ТабДок.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.DOCX) платформа преобразует координатную сетку ячеек 1С в одну сплошную таблицу Word (тег <w:tbl> в формате OpenXML).
  3. По спецификации Microsoft Word вставить символ жесткого разрыва страницы (<w:br w:type="page"/>) непосредственно между строками одной и той же таблицы невозможно без полного физического рассечения таблицы на две отдельные. Поэтому внутренний конвертер 1С полностью игнорирует добавленные горизонтальные разделители.

Рассмотрим рабочие альтернативы, позволяющие получить корректный документ Word с четкой разбивкой по страницам.

Способ 1. Формирование документа через COM-объект Word.Application

Если для бизнес-логики принципиально иметь документ в формате Word и выводить промежуточные итоги, самым гибким подходом является создание документа напрямую через Automation-сервер. Для этого создадим COM-объект и настроим правила переноса строк таблицы.

Посмотрим на пример базовой инициализации документа из 1С:


Word1C = Новый COMОбъект("Word.Application");
Word1C.Visible = Ложь;
НовыйДокумент = Word1C.Documents.Add();

В модели Word существует несколько ключевых параметров, позволяющих управлять разрывами строк и абзацев:

  1. Запрет разрыва строки пополам. Чтобы параграф или строка таблицы не разрезались снизу листа (когда пара строк остается на одном листе, а хвост уходит на другой), необходимо у строки таблицы установить свойство AllowBreakAcrossPages = Ложь. В этом случае вся строка целиком автоматически перенесется на следующий лист, если не помещается внизу страницы.
  2. Принудительный перенос строки на следующий лист. Если требуется жестко начать строку таблицы с чистого листа без разрыва самой таблицы, используется не вставка символа разрыва, а свойство абзаца ячейки:
    
    Ячейка = ТаблицаWord.Cell(НомерСтроки, 1);
    Ячейка.Range.ParagraphFormat.PageBreakBefore = Истина;
    
    В разметке Word это формирует тег <w:pageBreakBefore/>, оставляя таблицу целостной, но отправляя нужную строку на новую страницу.
  3. Связка с последующим блоком. Чтобы строка с промежуточным итогом гарантированно не отрывалась от следующего за ней блока, используется свойство KeepWithNext = Истина.

Способ 2. Программный контроль конца страницы в Word

В объектной модели Word нет прямого аналога функции ТабДок.ПроверитьВывод(), так как компоновка страниц в текстовом процессоре рассчитывается «на лету» в зависимости от драйвера печати и параметров шрифта. Однако мы можем динамически считывать номер текущей страницы через свойство Range.Information.

Константа wdActiveEndPageNumber имеет числовое значение 3. Разберем алгоритм отслеживания перехода на новую страницу:


ТекущаяСтраница = 1;

Для Каждого СтрДанных Из ТаблицаДанных Цикл
    // Добавляем строку в таблицу Word
    НоваяСтрока = ТаблицаWord.Rows.Add();
    НоваяСтрока.AllowBreakAcrossPages = Ложь;
    НоваяСтрока.Cells(1).Range.Text = СтрДанных.ТекстПараграфа;
    
    // Проверяем, на какой физической странице оказалась ячейка
    ФактическаяСтраница = НоваяСтрока.Cells(1).Range.Information(3);
    
    Если ФактическаяСтраница > ТекущаяСтраница Тогда
        // Произошел переход на новый лист
        // Здесь можно отменить последнюю строку, вывести промежуточный итог
        // и перенести вывод данных дальше
        ТекущаяСтраница = ФактическаяСтраница;
    КонецЕсли;
КонецЦикла;

Такой подход позволяет динамически подсчитывать итоги по каждой странице документа Word непосредственно в процессе генерации.

Способ 3. Модификация разметки document.xml внутри файла DOCX

Если на сервере 1С не установлен Microsoft Office или генерация через COM работает слишком медленно, можно воспользоваться структурой файла .docx, который по своей сути представляет собой обычный ZIP-архив.

Рассмотрим по шагам этот вариант:

  1. В табличном документе 1С вместо метода ВывестиГоризонтальныйРазделительСтраниц() выводим в отдельную строку текстовый маркер-метку, например, ###PAGE_BREAK###.
  2. Сохраняем табличный документ стандартным вызовом ТабДок.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.DOCX).
  3. С помощью объекта 1С ЧтениеZipФайла распаковываем полученный файл во временный каталог.
  4. Открываем файл word/document.xml через ЧтениеТекста или ЧтениеXML.
  5. Находим фрагменты с маркером и заменяем их либо на закрытие текущей таблицы, вставку разрыва страницы <w:p><w:r><w:br w:type="page"/></w:r></w:p> и открытие новой таблицы, либо добавляем тег <w:pageBreakBefore/> в свойства абзаца ячейки (<w:pPr>).
  6. Упаковываем файлы обратно с помощью объекта ЗаписьZipФайла с расширением .docx.

Этот метод работает автономно на стороне сервера Linux или Windows без использования COM-объектов.

Способ 4. Выгрузка в формат PDF

Проанализируем еще одну простую и надежную альтернативу. Если основная цель задачи — гарантировать неизменность макета и точное соответствие печатной форме 1С (где ПроверитьВывод() и разделители отработали штатно), целесообразно выгружать результат в PDF:

ТабДок.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.PDF);

Формат PDF гарантирует сохранение всех колонтитулов, разрывов страниц и промежуточных итогов в точности так, как их рассчитала платформа 1С. При необходимости редактирования современные версии офисных пакетов позволяют открывать PDF-документы и автоматически преобразовывать их в формат Word с сохранением разбиения на страницы.

← На главную