Pull to refresh

Публикация DITA в PDF с использованием DITA Open Toolkit. Разметка страниц — обзор layout-master

Reading time 12 min
Views 5.3K
В предыдущей статье я сделал небольшой обзор, дающий общее представление о публикации DITA в PDF. Теперь я решил рассказать, как в XSL-FO осуществляется разметка страниц будущего документа и о том, как это реализовано в базовой конфигурации DITA-OT.
Использованы материалы книги «Dave Pawson, XSL-FO — Making XML Look Good in Print, 2002».

Структура документа


Любой документ в XSL-FO принято подразделять на три логические части:
  1. front matter — лицевая часть, которая включает в себя титульный лист, аннотацию, оглавление, список иллюстраций и т.п.
  2. main matter (или body) — основная часть, которая содержит непосредственно текст документа, таблицы, иллюстрации и пр.
  3. back matter — задняя часть, которая содержит индексы, глоссарии, библиографический список и т.п.

Стоит отметить, что это структура конечного документа с точки зрения XSL-FO. Исходный документ DITA обычно содержит только текст (таблицы и иллюстрации). Элементы DITA содержат атрибуты, значения которых также играют роль при публикации (используемый язык, выравнивание, привязка к соседним элементам и пр.). Оглавление, списки и индексы, титульный лист — эти части документа формируются автоматически на основе исходного содержимого.
В конечном документе могут отсутствовать лицевая и/или задняя часть, либо они могут быть объединены с основной частью. Основная часть существует всегда.

Файлы, в которых описывается разметка


Для каждой составной части документа может использоваться своя разметка страницы. Все разметки (типы страниц) описываются в файле layout-masters.xsl, расположенном в папке ..\org.dita.pdf2\cfg\fo.
Наборы параметров для каждой разметки задаются в файле layout-masters-attr.xsl, который расположен в папке ..\org.dita.pdf2\cfg\fo\attrs.
Значения параметров в наборах либо задаются явно, либо в виде ссылки на другой параметр. Параметр, на который указана ссылка, должен быть задан явно в каком-либо из файлов параметров.

Элементы, отвечающие за разметку


Корневым элементом XSL-FO документа является fo:root. Преобразование для него расположено в файле ..\org.dita.pdf2\xsl\fo\root-processing.xsl. Его дочерним элементом, который содержит разметку всех типов страниц, является fo:layout-master-set (см. рисунок).

Элемент fo:layout-master-set в свою очередь содержит два дочерних элемента:
  1. fo:simple-page-master — содержит описание разметки страниц определенной части документа (например, оглавления)
  2. fo:page-sequence-master — генерирует последовательность страниц с определенной разметкой. При формировании документа в эти последовательности распределяется исходный контент DITA.

И тот и другой элемент имеют уникальное имя, которое указывается в параметре master-name. По нему при формировании документа происходит вызов требуемой разметки страницы. Вызов осуществляется из элементов fo:page-sequence, которые предназначены для распределения содержимого DITA по страницам с требуемой разметкой. fo:page-sequence ссылается на fo:simple-page-master или fo:page-sequence-master через параметр master-reference.

Возникает вопрос — зачем использовать fo:page-sequence-master, если можно ссылаться на fo:simple-page-master напрямую. Дело в том, что для одного и того же типа разметки можно использовать подтипы: для первой страницы раздела, для последней страницы, для четных страниц, для нечетных страниц. Для каждого подтипа также как и для основного типа задается свой набор параметров. А fo:page-sequence-master позволяет по входным параметрам динамически определять, какой тип разметки должен быть использован. Если же вызывать fo:simple-page-master напрямую, то мы должны заранее знать, какую разметку выбрать, что не всегда выполнимо.

В DITA-OT имена подтипов заданы следующим образом:
  • для первой страницы к имени основного типа добавляют -first;
  • для последней — -last;
  • для нечетных — -odd;
  • для четных — -even;
  • для пустых страниц — -blank.

Simple Page Master


Как я уже сказал выше, элемент fo:simple-page-master предназначен для описания разметки страниц определенной части документа.
В XSL-FO любая страница содержит пять рабочих областей (см. рисунок):
  • region-body — основная область страницы, в которой размещается содержимое документа;
  • region-before — верхний колонтитул;
  • region-after — нижний колонтитул;
  • region-start — левое поле (для направления текста слева направо);
  • region-end — правое поле (для направления текста слева направо).

Каждая область имеет имя. По умолчанию оно соответствует названию элемента. Имя можно задать в параметре region-name. Имя области используется, чтобы при формировании документа указывать, в какую область какие данные выводить. Например, статичные данные fo:static-content чаще всего выводятся в колонтитулы или на поля.

Каждой области в XSL-FO соответствует одноименный элемент (в пространстве имен fo). Все эти элементы являются дочерними по отношению к fo:simple-page-master.

Параметры Simple Page Master


Элемент fo:simple-page-master имеет следующие параметры:
  • master-name — уникальный идентификатор разметки.
  • page-height — высота страницы.
  • page-width — ширина страницы.
  • margin-top, margin-bottom, margin-left и margin-right — размеры полей страницы. Следует отличать их от колонтитулов и полей, являющихся рабочими областями.
  • reference-orientation — ориентация верха страницы (угол в градусах против часовой стрелки) относительно значения по умолчанию. Может принимать значения: -270, -180, -90, 0, 90, 180, 270. По умолчанию — 0.
  • writing-mode — режим, определяющий расположение областей и блоков (параграфов, таблиц, иллюстраций и т.д.) на странице. Существует три режима: lr-tb (слева направо, сверху вниз), rl-tb (справа налево, сверху вниз), tb-rl (сверху вниз, справа налево). Первая часть названия режима указывает направление текста в строках, вторая — направление следования блоков в пределах области.

На рисунке ниже изображено расположение областей на странице в зависимости от параметров reference-orientation и writing-mode.


Размеры областей


Каждая из областей (кроме region-body) имеет параметр extent, определяющий размер области в направлении перпендикулярном соответствующей стороне страницы. Для колонтитулов — это высота, для полей — ширина. Задается в единицах длины, либо в процентах от соответствующего размера страницы (параметры page-height и page-width).

Область region-body


Размеры области region-body определяются иным образом. Во-первых, они ограничиваются размерами полей страницы. Во-вторых, она имеет 4 параметра: margin-top, margin-bottom, margin-left и margin-right, которые определяют отступы границы области region-body от области content rectangle of the page reference area, обозначенной штрихом на втором рисунке. Эти отступы могут быть заданы в единицах длины или в процентах от размера области content rectangle of the page reference area.
Здесь следует сделать достаточно значимый вывод, что границы области region-body не зависят от размеров и параметров соседних областей.

Отступы области region-body расположены в соответствии с ориентацией страницы. Например, если для страницы задана ориентация 90, то верхний отступ отсчитывается от этого направления. Если для region-body задана своя ориентация (параметр reference-orientation), это никак не влияет на расположение отступов. Они все равно отсчитываются в соответствии с ориентацией страницы. Ориентация области region-body влияет только на то, как будут располагаться в ней дочерние блоки.

Для области region-body может быть задано количество колонок, в которых будет размещено содержимое документа. За это отвечают два параметра: column-count — задает количество колонок (должно быть больше или равно 1); column-gap — расстояние между соседними колонками.

Выравнивание в областях


Для выравнивания в областях предназначен параметр display-align, который может принимать значения: auto, before, center, after. Он определяет выравнивание дочерних блоков в области в направлении их следования, которое указано в параметре writing-mode.

А что с углами?


Два верхних угла страницы могут быть заняты либо верхним колонтитулом либо левым и правым полями. Аналогично, нижние углы — нижним колонтитулом либо левым и правым полями. За это отвечает параметр precedence, указываемый для колонтитулов. Если параметр имеет значение true, то углы занимает колонтитул (тот, для которого параметр указан). Если параметр имеет значение false, то углы занимают поля. По умолчанию параметр имеет значение false.

Page Sequence Master


Элемент fo:page-sequence-master, как я упоминал, предназначен для создания последовательности страниц, в которую при формировании документа будет распределяться исходный контент DITA.
Этот элемент имеет три дочерних элемента:
  • fo:single-page-master-reference — используется, когда требуется сформировать последовательность из одной страницы. Например, титульный лист документа. При работе с элементом fo:single-page-master-reference следует помнить, что, если одной страницы не хватает для размещения исходного контента, это вызовет ошибку при публикации.
  • fo:repeatable-page-master-reference — используется для формирования ограниченных или неограниченных последовательностей страниц с одинаковой разметкой. При использовании элемента fo:repeatable-page-master-reference может быть указано предельное число страниц, которое будет сформировано. Для этого служит параметр maximum-repeats. По умолчанию число страниц неограничено.
  • fo:repeatable-page-master-alternatives — используется для формирования нескольких последовательностей с разной разметкой в зависимости от указанных параметров. Является наиболее гибким инструментом.

Условия выбора разметки в элементе fo:repeatable-page-master-alternatives задаются с помощью дочерних элементов fo:conditional-page-master-reference. Каждое условие может содержать от одного до трех параметров, в совокупности определяющих, выполнено условие или нет.
Это следующие параметры:
  • page-position — расположение страницы в разделе — first (первая), last (последняя), rest (не первая и не последняя), any (любая).
  • odd-or-even — четность номера страницы — odd (нечетная), even (четная), any (любая).
  • blank-or-not-blank — имеет ли страница данные переданные из блока fo:flowblank (пустая), not-blank (не пустая), any (любая).
  • для fo:repeatable-page-master-alternatives также может быть задано предельное число страниц в параметре maximum-repeats.

Немного о fo:page-sequence


Итак, разметки описаны, условия выбора заданы, как же теперь их вызывать из XSLT преобразования?
Для этого служит элемент fo:page-sequence. Он имеет обязательный параметр master-reference, в котором указывается имя вызываемой разметки.

Также в элементе могут быть указаны параметры, отвечающие за нумерацию страниц.

Параметр initial-page-number фиксирует номер первой страницы генерируемой последовательности страниц:
  • auto — продолжает нумерацию предыдущего раздела;
  • auto-odd — продолжает нумерацию с первого нечетного номера;
  • auto-even — продолжает нумерацию с первого четного номера;
  • конкретное число, с которого начнется нумерация.

Параметр force-page-count накладывает условие на количество страниц генерируемой последовательности:
  • auto — устанавливает количество страниц в соответствии с номером первой страницы следующей последовательности;
  • even — жестко устанавливает четное количество страниц;
  • odd — жестко устанавливает нечетное количество страниц;
  • end-on-even — номер последней страницы четный;
  • end-on-odd — номер последней страницы нечетный;
  • no-force — не регламентируется.

А как оно в DITA-OT?


Очень много теории, а как же все это реализовано в DITA Open Toolkit.
Если в общих словах, сначала описываются все типы разметок simple-page-master (для обложки, оглавления и т.д.). Далее, по теории, должны быть описаны последовательности страниц page-sequence-master для каждой разметки.
В DITA-OT для этого используется XSL шаблон generate-page-sequence-master, который генерирует последовательность страниц по указанным параметрам.
Шаблон отрабатывает несколько раз из call-template. Каждый вызов генерирует последовательность для одного типа разметки в соответствии с указанными параметрами.

Все это мы можем увидеть в файле layout-masters.xsl, расположенном в папке ..\org.dita.pdf2\cfg\fo.
В строке 43 мы видим начало элемента fo:layout-master-set, в котором расположены элементы fo:simple-page-master, каждый из которых содержит описание отдельной разметки.

Например, первые четыре штуки — для обложки:
<fo:simple-page-master master-name="front-matter-first" xsl:use-attribute-sets="simple-page-master">
    <fo:region-body xsl:use-attribute-sets="region-body__frontmatter.odd"/>
</fo:simple-page-master>

<fo:simple-page-master master-name="front-matter-last" xsl:use-attribute-sets="simple-page-master">
    <fo:region-body xsl:use-attribute-sets="region-body__frontmatter.even"/>
    <fo:region-before  region-name="last-frontmatter-header" xsl:use-attribute-sets="region-before"/>
    <fo:region-after region-name="last-frontmatter-footer" xsl:use-attribute-sets="region-after"/>
</fo:simple-page-master>

<xsl:if test="$mirror-page-margins">
    <fo:simple-page-master master-name="front-matter-even" xsl:use-attribute-sets="simple-page-master">
        <fo:region-body xsl:use-attribute-sets="region-body__frontmatter.even"/>
        <fo:region-before region-name="even-frontmatter-header" xsl:use-attribute-sets="region-before"/>
        <fo:region-after region-name="even-frontmatter-footer" xsl:use-attribute-sets="region-after"/>
    </fo:simple-page-master>
</xsl:if>

<fo:simple-page-master master-name="front-matter-odd" xsl:use-attribute-sets="simple-page-master">
    <fo:region-body xsl:use-attribute-sets="region-body__frontmatter.odd"/>
    <fo:region-before region-name="odd-frontmatter-header" xsl:use-attribute-sets="region-before"/>
    <fo:region-after region-name="odd-frontmatter-footer" xsl:use-attribute-sets="region-after"/>
</fo:simple-page-master>

  • Первая разметка, исходя из названия, предназначена для первой страницы обложки. Она имеет только основную область region-body, для которой применяется набор атрибутов region-body__frontmatter.odd. Хотя этот набор предназначен для нечетных страниц (судя по названию), ничто не мешает использовать его здесь. Набор атрибутов описан в файле layout-masters-attr.xsl.
  • Вторая разметка — для последней страницы обложки. Она имеет основную область, верхний и нижний колонтитул. При этом колонтитулы имеют собственные имена last-frontmatter-header и last-frontmatter-footer, основная область имеет имя по умолчанию — region-body.
  • Третья разметка — для четных страниц обложки — используется только при выполнении условия, указанного в элементе xsl:if. Если булевая переменная $mirror-page-margins имеет значение true, то для нечетных и четных страниц используется разная разметка (как правило — зеркальная).
  • Четвертая разметка — для нечетных страниц обложки — не ограничивается условием четности страницы. Однако, если $mirror-page-margins имеет значение true, то она вызывается только для нечетных страниц. Это можно увидеть в fo:page-sequence-master ниже.

Далее после объявления всех разметок генерируются последовательности страниц page-sequence-master (строка 169), в которые при формировании документа будет распределяться поток данных из топиков DITA.

Например, следующий код генерирует последовательность страниц для оглавления (toc — table of content):
<xsl:call-template name="generate-page-sequence-master">
    <xsl:with-param name="master-name" select="'toc-sequence'"/>
    <xsl:with-param name="master-reference" select="'toc'"/>
</xsl:call-template>

Для создания каждой последовательности вызывается XSL шаблон generate-page-sequence-master с соответствующими параметрами в элементах xsl:with-param. В параметрах: name — имя параметра, select — значение параметра.

В конце файла описан XSL шаблон generate-page-sequence-master, который генерирует последовательность страниц page-sequence-master в соответствии с входными параметрами (см. последний листинг). В базовой конфигурации DITA-OT используются только универсальный fo:repeatable-page-master-alternatives, и в зависимости от входных параметров выбирается та или иная разметка.

Шаблон имеет четыре параметра:
  • master-name — устанавливает имя для генерируемой последовательности. По этому имени последовательность будет выбираться при распределении исходного содержимого DITA.
  • master-reference — имя разметки, которая будет вызвана для генерации последовательности.
  • first — признак того, что это первая страница. По умолчанию true.
  • last — признак того, что это последняя страница. По умолчанию true.

Далее в шаблоне создается page-sequence-master с именем, указанным в параметре master-name шаблона. Значение параметра передается как переменная $master-name. Элемент page-sequence-master содержит один дочерний fo:repeatable-page-master-alternatives, который содержит три условия:
  1. xsl:if test="$first" — является ли страница первой в последовательности;
  2. xsl:if test="$last" — является ли страница последней в последовательности;
  3. xsl:when test="$mirror-page-margins" — используется ли разная разметка для четных и нечетных страниц.

Если страница первая, то conditional-page-master-reference вызывает разметку по имени, указанном в переменной $master-reference для первой страницы (к имени добавляется -first), с параметрами: odd-or-even=«odd» (нечетная страница) и page-position=«first» (первая страница).
Если страница последняя, то conditional-page-master-reference вызывает разметку по имени, указанном в переменной $master-reference для последней страницы (к имени добавляется -last), с параметрами: odd-or-even=«even» (четная страница), page-position=«last» (последняя страница) и blank-or-not-blank=«blank» (пустая страница).
Если учитывается четность страниц, то используются два conditional-page-master-reference: для четных и для нечетных страниц. В противном случае (xsl:otherwise) используется разметка для нечетных страниц.

<xsl:template name="generate-page-sequence-master">
    <xsl:param name="master-name"/>
    <xsl:param name="master-reference"/>
    <xsl:param name="first" select="true()"/>
    <xsl:param name="last" select="true()"/>
    <fo:page-sequence-master master-name="{$master-name}">
        <fo:repeatable-page-master-alternatives>
            <xsl:if test="$first">
                <fo:conditional-page-master-reference master-reference="{$master-reference}-first"
                                                      odd-or-even="odd"
                                                      page-position="first"/>
            </xsl:if>
            <xsl:if test="$last">
                <fo:conditional-page-master-reference master-reference="{$master-reference}-last"
                                                      odd-or-even="even"
                                                      page-position="last"
                                                      blank-or-not-blank="blank"/>
            </xsl:if>
            <xsl:choose>
                <xsl:when test="$mirror-page-margins">
                    <fo:conditional-page-master-reference master-reference="{$master-reference}-odd"
                                                          odd-or-even="odd"/>
                    <fo:conditional-page-master-reference master-reference="{$master-reference}-even"
                                                          odd-or-even="even"/>
                </xsl:when>
                <xsl:otherwise>
                    <fo:conditional-page-master-reference master-reference="{$master-reference}-odd"/>
                </xsl:otherwise>
            </xsl:choose>
        </fo:repeatable-page-master-alternatives>
    </fo:page-sequence-master>
</xsl:template>
Tags:
Hubs:
+6
Comments 0
Comments Leave a comment

Articles