Анализ технико-экономических показателей разработки и эксплуатации ПП 3 страница
Таблица 3.6 | |
Атрибут | Описание |
font-family | Название шрифта |
font-size | Размер шрифта |
Text-align | Положение текста в блоке |
Start-indent | Отступ слева |
end-indent | Отступ справа |
Размер шрифта указывается так: font-size=”14pt”. Атрибут text-align, указывающий положение текста в блоке, может принимать следующие значения: center, left, right. Отступы слева и справа указываются в миллиметрах.
По умолчанию границы блока невидимы, но с помощью специальных атрибутов можно указать fop-процессору, где их необходимо нарисовать. Также можно указать толщину линий, в противном случае она будет принята по умолчанию 3.6 мм. Атрибуты, используемые для задания границ и их толщины, представлены в таблице 3.7.
Таблица 3.7 | |
Атрибут | Описание |
border-style | Границы для всего блока |
Border-before-style / border-top-style | Граница перед текстом |
border-after-style / border-bottom-style | Граница после текста |
Border-start-style / border-left-style | Граница слева |
border-end-style / border-right-style | Граница справа |
border-width | Толщина границы для всего блока |
border-before-width / border-top-width | Толщина границы перед текстом |
Border-after-width / border-bottom-width | Толщина границы после текста |
Border-start-width / border-left-width | Толщина границы слева |
Border-end-width / border-right-width | Толщина границы справа |
Объект fo:block-container предназначен для группировки нескольких блоков, либо для задания некоторых свойств конкретного блока. В рассматриваемой спецификации в некоторых ячейках штампа текст располагается вертикально. Для того, чтобы в шаблоне XSL задать поворот текста на 90 градусов, необходимо воспользоваться атрибутом reference-orientation, принадлежащем элементу fo:block-container. При этом нужно разрешить поворот текста с помощью атрибута position, присвоив ему значение absolute [4]. Для того, чтобы опустить или приподнять текст, используют атрибут top. Если необходимо текст опустить, то указывается положительное значение отступа в миллиметрах, в противном случае – отрицательное.
Объект fo:table применяются для описания таблиц. К его прямым потомкам относятся следующие элементы: fo:table-column, fo:table-body, fo:table-row, fo:table-cell [2].
Элемент fo:table-column задаёт колонку в таблице. Последовательность из пяти таких объектов задаёт пять колонок, соответственно. С помощью атрибута column-number указывается порядковый номер колонки. При помощи column-width – её ширина.
Объект fo:table-body включает в себя узлы, описывающие строки и ячейки таблицы. Он задаёт рабочую зону таблицы. То есть в нём находится фактическое содержимое таблицы. В нём, с помощью соответствующих атрибутов, могут быть указаны свойства текста.
Элемент fo:table-row используется для группировки в строки ячеек таблицы. В нём с помощью атрибута line-height указывается высота строк.
Содержимое каждой ячейки размещается в объекте fo:table-cell. Пример использования элементов, описывающих представление таблиц, приведён ниже.
<fo:table>
<fo:table-column column-number="1" column-width="35mm"/>
<fo:table-column column-number="2" column-width="35mm"/>
<fo:table-column column-number="3" column-width="20mm"/>
<fo:table-body font-family="GOST_B" font-size="10pt" text-align="center">
<fo:table-row line-height="5.75mm" >
<fo:table-cell column-number="1" border-style="solid">
<fo:block> Инв. № подл. </fo:block>
</fo:table-cell>
<fo:table-cell column-number="2" border-before-style="solid" border-after-style="solid" border-right-style="solid">
<fo:block> Подп. и дата </fo:block>
</fo:table-cell>
<fo:table-cell column-number="3" border-before-style="solid" border-after-style="solid" border-right-style="solid">
<fo:block> Взам. инв. № </fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-body/>
<fo:table>
Как видно из приведённого примера, объекты форматирования можно указывать не только для блока, но и для ячейки. При этом атрибуты, указанные в дочерних элементах, перекрывают атрибуты, указанные в родительских элементах. Объекты, относящиеся непосредственно к форматированию текста, разрешено применять в любых тегах, описывающих представление таблиц.
В элементе fo:table-cell,можно указать, что ячейки таблицы должны перекрывать несколько рядов или колонок, установив атрибуты number-columns-spanned и number-row-spanned в целое числовое значение, соответствующее количеству перекрыываемых данной ячейкой рядов и колонок. Необязательный атрибут column-number может изменить номер колонки, с которой начинается перекрытие. По умолчанию это текущая колонка.
Для вывода номера страницы в документе необходимо указать в шаблоне элемент <fo:page-number/> [4].
В разрабатываемом шаблоне спецификации встречаются строки таблицы, не содержащие данных. В этом случае процессор форматирующих объектов Apache FOP не выделяет места в pdf-документе для данной строки. Он только рисует границы ячеек, если они заданы. Для того, чтобы fop-процессор выделил место под строку, необходимо добавить в неё данные, к примеру, пробел. Но, Apache FOP пропускает те пробелы, которые указаны в начале и в конце текстовой строки, а также пробеллы «стоящие сами по себе». Для того, чтобы указать символ пробела явно, нужно воспользоваться записью такого вида:  . Где 160 – код символа «пробел» в кодировке UTF-8. Рассматриваемый элемент   относится к объектным ссылкам, «границы» объектной ссылки указываются с помощью символов & и ;. Знак # указывает на то, что 160 – это код символа.
Если текст не помещается в ячейке таблицы, Apache FOP переносит его на новую строчку. В соответствии ГОСТ 2.113 – 75, многострочный текст в некоторых случаях может занимать одну строку таблицы. Для решения данной проблемы в случае с колонкой «Примечание» текст в PartList разбивается на две строки, данные которых помещаются соответственно в атрибуты: PRIMECHANIE_1 и PRIMECHANIE_2 разработанного XML документа. При этом уменьшается шрифт и задаются размеры для новых строк, входящих в ячейку. В результате текст располагается в ней в две строки, но принадлежит одной строке таблицы. В противном случае примечание выводится в атрибут PRIMECHANIE. Описанное представление ячейки таблицы приведено ниже.
<fo:table-cell border-after-style="solid" border-end-style="solid">
<fo:block font-size="14pt">
<xsl:value-of select="@PRIMECHANIE"/>
</fo:block>
<fo:block-container line-height="3.82mm" position="absolute">
<fo:block font-size="10pt">
<xsl:value-of select="@PRIMECHANIE_1"/>
</fo:block>
</fo:block-container>
<fo:block-container top="3.82mm" line-height="3.82mm" position="absolute">
<fo:block font-size="10pt">
<xsl:value-of select="@PRIMECHANIE_2"/>
</fo:block>
</fo:block-container>
</fo:table-cell>
Разработанный шаблон XSL, описывающий представление групповой спецификации по ГОСТ 2.113 – 75, приведён в приложении A.
3.4 Алгоритм преобразования исходного XML в новый XML
В соответствии с ГОСТ 2.113 – 75 в групповой спецификации отступы в виде строк между разделами могут задаваться в зависимости от требований организации. Как правило, первая и последняя строки основной области страницы должны быть пустыми. Не допускается разрыв в виде переноса на другой лист между наименованием раздела и соответствующими данными. Если данные заполняют не всю страницу, необходимо, добавить, пусты строки.
Средствами, предоставляемыми XSL и MSXSL, не возможно обеспечить выполнение всех перечисленных требований. В настоящей квалификационной работе для решения указанной проблемы разработано специальное приложение, преобразующее исходный xml-документ в новый xml-документ. В частности, это приложение определяет, где в таблице спецификации необходимо вставить «пустые» строки (<line FORM=" "/>), и добавляет их.
Приложение разработано на языке С++, имеет графический пользовательский интерфейс и использует библиотеки: MFC и Win32API. Процесс его реализации описан в пункте 4.
3.5 Использование MSXSL и Apache FOP
Для выполнения XSLT-инструкций, описанных в разработанном шаблоне, применим программу MSXSL. Для запуска преобразования xml-документа в fo-файл необходимо выполнить команду:
msxsl example.xml example.xsl /o example.fo
Где msxsl – это программный модуль, выполняющий преобразование. Example.xml – имя преобразуемого xml-файла. Example.xsl – имя применяемого xsl-шаблона. Следующий элемент указывает на то, что полученный в результате файл должен быть сохранен. Последний элемент указывает имя файла результата. В рассмотренном примере, в качестве параметров передаются только имена файлов. Подразумевается, что файлы находятся в одном каталоге с MSXSL. Если это не так, необходимо передать полный путь к тем, которые находятся в не рабочего каталога, рассматриваемого приложения.
После создания fo-файла, содержащего xml-данные и объекты форматирования, необходимо запустить приложение Apache FOP для преобразования его в pdf-файл.
На сегодняшний день рекомендуемая консорциумом World Wide Web версия fop-процессора 0.20.5. Но, по причине того, что программа этой версии не поддерживает возможность поворота текста, была выбрана последняя версия 0.93 [11].
Apache FOP, по умолчанию, не поддерживает шрифтов алфавита русского языка. Что бы их подключить, необходимо выполнить следующие действия (на примере Arial).
1 этап. Скопировать нужный файл шрифта (Arial.ttf) из каталога Windows в каталог fop-процессора (к примеру, в C:\fop-0.93\conf\Fonts).
2 этап. Выполнить следующую команду (для генерации описания шрифта):
java -cp C:\fop-0.93\build\fop.jar;C:\fop-0.93\lib\avalon-framework-4.2.0.jar;C:\fop-0.93\lib\commons-logging-1.0.4.jar;C:\fop-0.93\lib\commons-io-1.1.jar org.apache.fop.fonts.apps.TTFReader -d C:\fop-0.93\conf\Fonts\Arial.ttf C:\fop-0.93\conf\Fonts\Arial.xml
3 этап. Добавить запись в файл C:\fop-0.93\conf\fop.xconf, следующего вида (должна находиться внутри тэгов <fonts> </fonts>):
<font metrics-url="C:\fop-0.93\conf\Fonts\arial.xml" kerning="yes" embed- url="C:\fop-0.93\conf\Fonts\arial.ttf">
<font-triplet name="Arial" style="normal" weight="normal"/>
<font-triplet name="ArialMT" style="normal" weight="normal"/>
</font>
Запуск FOP производится с помощью команды:
C:\fop-0.93\fop -c C:\fop-0.93\conf\fop.xconf Example.fo Example.pdf.
Первый атрибут – это путь к исполняемому командному файлу, рассматриваемого приложения.
Второй предназначен для того, чтобы применился третий.
Третий атрибут – это путь к файлу с объявлением шрифтов.
Четвёртый атрибут – путь к fo-файлу.
Пятый атрибут – путь к pdf-файлу.
В рамках текущей главы:
- разработана структура xml-документа;
- разработаны xsl-шаблоны, описывающие преобразование и представление групповой спецификации;
- подключены шрифты, поддерживающие кириллицу, к приложению Apache FOP;
- выяснен формат командной строки для программ MSXSL и Apache FOP.
4 РАЗРАБОТКА КОНВЕРТЕРА XML-ПРЕДСТАВЛЕНИЙ ГРУППОВЫХ СПЕЦИФИКАЦИЙ НА СБОРОЧНОЕ ИЗДЕЛИЕ, В PDF-ФОРМАТ
4.1 Разработка приложения
4.1.1 Реализация пользовательского интерфейса
Для разработки интерфейса пользователя воспользуемся средствами, предоставляемыми Microsoft Visual Studio 2010 и библиотекой MFC. Использование которой возможно только при написании программ на языке Visual C++. Для создания проекта в рассматриваемой среде программирования, необходимо:
- запустить рассматриваемую программу (в случае, если она уже инсталлирована на ПК, иначе, сначала установить её);
- в меню «File» выбрать «New»;
- в открывшемся подменю щёлкнуть левой кнопкой мыши по «Project», рисунок 4.1;
- в открывшемся окне, в элементе, отображающем дерево проектов выбрать «Visual C++», а затем «MFC»;
- в дочернем окне с названием «Templates», выбрать «MFC Application»;
- указать имя создаваемого проекта (в нашем случае «XMLConverter»), и каталог, где он будет располагаться, как показано на рисунке 4.2;
- щёлкнуть «OK»;
- в открывшемся окне, во вкладке «Application Type», указать «Dialog based»;
- выбрать «Use MFC in a static library» (в этом случае все библиотеки MFC, при компиляции, будут упакованы в файл EXE, разрабатываемого приложения), как показано на рисунке 4.3;
- щелкнуть «Finish».
Рисунок 4.1
Рисунок 4.2
Рисунок 4.3
В созданном проекте, для редактирования диалогового окна, щёлкаем в меню по «View». В открывшемся списке выбираем «Resource View». В появившемся окне, в дереве представляющем ресурсы проекта, щёлкаем по элементу «Dialog». В раскрывшемся списке выбираем «IDD_XMLCONVERTOR_DIALOG», как показано на рисунке 4.4.
Рисунок 4.4
Для добавления элементов в форму, нам понадобится меню «Toolbox». Для его открытия необходимо щёлкнуть в меню «View» по элементу с соответствующим именем. Из появившегося диалогового меню будем использовать объекты: «Button», «Edit Control», «Combo Box», «Static Text», «List Control». На рисунке 4.5 показана часть меню «Toolbox».
Рисунок 4.5
Для того чтобы добавить элемент, достаточно щёлкнуть мышкой по выбранному объекту, и держа клавишу нажатой, перетащить его на редактируемый диалог. Для открытия окна свойств добавленного элемента необходимо, щёлкнуть по нему правой кнопкой мыши, выбрать, в появившемся контекстном меню, элемент «Properties» (Рисунок 4.6).
Добавим необходимые элементы к окну разрабатываемого приложения, как показано на рисунке 4.7. С помощью поля «Caption», свойств каждого объекта, приведём его заголовок в соответствие с рассмотренным рисунком.
Рисунок 4.6
Рисунок 4.7
Для того чтобы при запуске приложения кнопки: «Преобразовать xml в pdf» и «Удалить выбранный элемент» были не активны, нужно установить, в свойствах каждого элемента, значение поля «Disabled» в «True». Чтобы элемент «List Control» отображал колонки, необходимо в его свойствах, для поля «View» указать значение «Report». Для оконного объекта «Combo Box», в поле «Type» нужно выбрать значение «Drop List». Чтобы рассматриваемый объект содержал значения, воспользуемся полем Data, введя в него строку вида «ГрупСпец_Ф1_gost-B_0-9;ГрупСпец_Ф1_gost-B_10-19;ГрупСпец_Ф1_gost-B_20-29;». В которой через точку с запятой указан список значений элемента «Combo Box». Так как поле, в котором будет отображаться директория для вывода pdf-файлов, не должно подвергаться редактированию, установим его свойство «Read Only» в «True».
Добавим в класс разрабатываемой формы функции – обработчики событий, вызываемые по нажатию соответствующей кнопки. То есть, определим методы, каждый из которых будет вызываться при получении формой соответствующего сообщения от Windows. Для этого, в редакторе форм, два раза щелкнем по кнопке в окне разрабатываемой программы. Редактор Visual Studio автоматически добавит функцию – обработчик сообщения «ON_BN_CLICKED» (отправляемого Windows приложению при щелчке левой кнопкой мыши по элементу «Buttom»), которое поступит в очередь и обработается приложением в порядке следования. Так как сообщения обрабатываются программой очень быстро, щёлчек пользователя по описываемой кнопке, запущенного на выполнение приложения, вызовет соответствующую функцию практически мгновенно. Таким образом добавляются обрабочки событий щелчка левой кнопки мыши для каждого объекта «Buttom».
Для элемента формы типа «List Control», с идентификатором ресурса «IDC_LIST1» определим три обработчика следующих сообщений: «LVN_ITEMCHANGED», «LVN_DELETEITEM», «LVN_ITEMACTIVATE». Первый будет вызываться при выборе элемента, рассматриваемого объекта. Второй при его удалении. Третий при двойном щелчке мышкой по элементу. Для их добавления, необходимо щёлкнуть правой кнопкой мыши по рассматриваемому элементу, в окне редактора форм, и в появившемся меню выбрать «Add Event Handler». В выведенном окне (Рисунок 4.8): выбрать сообщение; указать класс (в данном случае «CXMLConverterDlg»), в который будет добавлена функция; ввести имя добавляемого метода в поле с названием «Function handler name» или оставить предложенное по умолчанию. После выполнения описанных действий щёлкнуть по кнопке «Add and Edit».
Рисунок 4.8
В рассматриваемом элементе формы должны отображаться три столбца. Для определения их количества, размеров и имён заголовков напишем следующий фрагмент программного кода.
CListCtrl *pList = (CListCtrl*) GetDlgItem(IDC_LIST1);
pList->InsertColumn(0,_T("Полный путь к xml-файлу"),0,370,-1);
pList->InsertColumn(1,_T("Статус"),0,100,-1);
pList->InsertColumn(2,_T("Состояние"),0,100,-1);
Здесь, с помощью функции GetDlgItem( ) получаем указатель на оконный элемент с идентификатором «IDC_LIST1». Метод InsertColumn() создаёт колонку. В него в качестве параметров передаются: порядковый номер, название, положение текста (0 означает, что текст будет выравниваться по левому краю), ширина, связь с другими колонками (если значение -1, связи нет). Макрос _T( ) применяется для преобразования строки в Unicode. Рассмотренный фрагмент кода необходимо поместить в виртуальную функцию OnInitDialog( ), которая вызывается Windows при инициализации диалогового окна [6].
Данные выводятся в «IDC_LIST1» с помощь функций: InsertItem( ) и SetItem( ). Первый метод используется для добавления элементов в главный (первый) столбец. Второй для добавления элементов в дочнрние столбцы. В качестве параметра в каждую из функций передается указатель на структуру типа «LV_ITEM». Которая содержит переменные определяющие: номер (позицию) элемента в строке, номер столбца, выводимый текст, максимальную длину выводимой строки. Структура инициализируется перед вызовом функций: InsertItem() и SetItem() [6]. Демонстрационный пример кода представлен ниже.
CListCtrl *pList = (CListCtrl*) GetDlgItem(IDC_LIST1);
LV_ITEM lvitem;
lvitem.mask = LVIF_TEXT;
lvitem.iItem = 0;
lvitem.iSubItem = 0;
lvitem.pszText = str.GetBuffer();
lvitem.cchTextMax = lstrlen(str);
pList->InsertItem(&lvitem);
lvitem.iSubItem = 1;
lvitem.pszText = _T("Не выполнено");
lvitem.cchTextMax = lstrlen(_T("Не выполнено"));
pList->SetItem(&lvitem);
Флаг «LVIF_TEXT» разрешает вывод текста. Переменная str строкового типа CString, который является классом входящем в MFC и предоставляет широкие возможности работы со строкой. Переменная данного типа является динамической, то есть память под нее выделяется по мере необходимости. Так как переменная pszText, структуры lvitem, должна присвоить указатель, адресующий статический блок памяти, необходимо сделать его таковым. Для этого применяется метод класса CString именуемый GetBuffer() [6].
Чтобы считать данные из элемента типа «List Control», нужно заменить в рассмотренном коде вызов функции InsertItem() на GetItem(). После её выполнения в переменной str окажется текст требуемой ячейки.
Чтобы удалить необходимую строку, используют функцию DeleteItem(), как показано ниже.
CListCtrl *pList = (CListCtrl*) GetDlgItem(IDC_LIST1);
pList->DeleteItem(m_nSelectItem);
Где m_nSelectItem – порядковый номер удаляемой строки. Весь элемент «List Control» очищают с помощью метода DeleteAllItems().
Для ввода полного пути к преобразуемому xml-файлу, воспользуемся стандартным диалоговым классом CFileDialog, предоставляемым MFC. Объявим переменную типа этого класса. Определим значения три, которые будут передаваться его конструктору. Нас интересуют первый и третий атрибут. Первый, определяет, будет ли диолог открывать файл или напротив его сохранять. Второй установим в 0. Третий, указывает, какого типа файлы будут видны в диалоге. Для запуска построения модального диалогового окна открытия файла воспользуемся функцией DoModal( ). Данный метод возвратит управление основному окну приложения только после закрытия им вызванного.
То есть, пользователь не сможет обратится к главному окну, пока не закроет дочернее. Код реаализующий описанные события представлен ниже.
CFileDialog fdialog(TRUE,0,_T("*.xml"));
fdialog.DoModal();
Для выбора директории в которую будут сохраняться pdf-файлы, воспользуемся стандартным диалогом Windows. Для этого объявим структуру BROWSEINFO, присвоим переменным, принадлежащем ей, значения, как показано ниже.
wchar_t sDir[512];
BROWSEINFO brinfo;
brinfo.hwndOwner = 0;
brinfo.pidlRoot = 0;
brinfo.pszDisplayName = sDir;
brinfo.lpszTitle =_T("Выберите папку для вывода pdf-файлов");
brinfo.ulFlags = BIF_RETURNONLYFSDIRS;
brinfo.lpfn = 0;
brinfo.lParam = 0;
Для вывода диалогового окна воспользуемся функцией SHBrowseForFolder(&brinfo). Которая возвращает значение типа LPITEMIDLIST. Используя переменную рассмотренного типа и функцию SHGetPathFromIDList() получим путь к выбранной пользователем папке. Пример представлен ниже.
LPITEMIDLIST pDirList = SHBrowseForFolder(&brinfo);
SHGetPathFromIDList(pDirList,sDir);
В результате будет выводится диалог представленный на рисунке 4.9.
Рисунок 4.9
Для того, чтобы сделать не активными кнопки программы необходимо воспользоваться функциями: GetDlgItem() и EnableWindow(). Первая возврвщает указатель на объект. Вторая делает его пассивным, либо активным, в зависимости от значений FALSE или TRUE, соответственно. Применение этих функций продемонстрированно ниже.
GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE);
Для предусмотрения возможности ввода количества отступов до и после раздела в генерируемой спецификации, создадим с помощью редактора форм диалоговое окно. Для этого в меню «Resource View» (Рисунок 4.4) нужно щёлкнуть правой кнопкой мыши по элементу «Dialog» и выбрать «Add Resource». В появившемся окне (Рисунок 4.10) выбрать «Dialog» и щёлкнуть «New». В результате в проект будет добавлен новый шаблон диалога. После выполнения ряда действий, принципы проведения которых были описаны ранее, получется диалоговое окно представленное на рисунке 4.11.
Рисунок 4.10
Рисунок 4.11
После создания формы диалога, необходимо добавить для нее класс в проект. Для этого необходимо щёлкнуть правой кнопкой мыши по форме и в появившемся контекстном меню выбрать «Add Class». В выведенном на экран окне указать имя создаваемого класса «CSetting» в поле «Class name». В качестве базового класса, методы которого будут наследоваться, оставить предложенный по умолчанию CDialog. Щелкнуть «Finish». При добавлении событий для элементов формы, их обрабочики будут помещаться в определённый для них класс Setting. То есть, в только что созданный. Далее неообходимо указать заголовочный файл нового диалога в cpp-файле основного диалога. Затем внести объявление класса в виде записи «class CSetting» в заголовочный файл класса CXMLConverterDlg. Для вызова окна представленного на рисунке 4.11 при щелчке мышкой по кнопке в главном диалоге, необходимо внести в обработчик соответствующего события код представленный ниже.
CSitting *pSitting = new CSitting();
pSitting->DoModal();
delete[] pSitting;
Для того, чтобы считывать и хранить значения вносимые в элемент «Edit Controll» необходимо добавить переменную. Для этого в редакторе форм необходимо щёлкнуть правой кнопкой мыши по нужному объекту, выбрать в меню «Add Variable». В появившемся окне указать категорию, имя и тип переменной. Возможно так же ввести минимальное и максимальное её значения. Пример представлен на рисунке 4.12.
Рисунок 4.12
В результате выполнения работ описанных в текущей главе, был разработан пользовательский интерфейс приложения XMLConverter.
4.1.2 Разработка функций реализующих алгоритм преобразования исходного XML в новый XML
Во время выполнения настоящей квалификационной работы был разработан алгоритм преобразования xml-документа в промежуточный xml-документ. При его рассмотрении примем во внимание, что все расчёты количества добавляемых строк ведутся с учётом заданных величин отступов сверху и снизу для разделов в спецификации. Отступы представлены в виде пустых строк. Введём в алгоритм счётчик общего количества строк i. Он нужен для контроля позиции текущего элемента, а также, чтобы вычислить количество пустых строк, которые необходимо добавить в конец xml-документа. Перед запуском алгоритма i равно 0. Под элементами будем понимать, теги <line/> и <section/>. Преобразование рассматривается на уровне этих объектов. Рассматривая их, будем иметь в виду, что они несут с собой данные, хранимые в атрибутах. Каждый из этих элементов (<line/> и <section/>) образует строку таблицы спецификации. То есть, говоря о строке pdf-документа, будем подразумевать, что это <line/> или <section/> xml-документа и наоборот.
Алгоритм состоит из следующих шагов.
1 этап. Увеличиваем счётчик на единицу. Рассматриваем i-ю строку xml-документа. Если это <section/>, переходим к этапу 2. Иначе переходи к этапу 5.
2 этап. Проверяем, не попадёт ли раздел на вторую строку страницы спецификации, при добавлении пустых строк (по одной, начиная с нуля) сверху, в пределах заданного отступа. Если да, вносим необходимое число пустых элементов <line/> и увеличиваем счётчик на количество добавленных строк. Переходим к этапу 7. Иначе, увеличиваем счётчик на величину заданного отступа. Переходим к этапу 3.
3 этап. Проверяем, не получается ли разрыв между разделом и первой не пустой строкой, после него, в виде переноса последней на другой лист спецификации, при добавлении пустых строк (по одной, начиная с нуля) снизу, в пределах заданного отступа. Если да, добавляем перед <section/> необходимое число <line/>, сдвигая, таким образом, раздел на вторую строку следующего листа. Увеличиваем счётчик на число добавленных строк. Переходим к этапу 7. В противном случае переходим к этапу 4.