# DITA XML and XSL-FO tutorials

> **Note: Legacy toolchain**
>
> These tutorials document a specific publishing architecture: DITA XML sources rendered to PDF and other formats through XSL-FO style sheets. They remain useful if you maintain or customize a pipeline of this kind. To choose an authoring model for a new project, see [choose an authoring model](https://docs.redaction-technique.org/en/tools-and-formats/).

## Overview

The following tutorials will help the technical writer set up and use a free DITA XML authoring and publishing chain. For a broader overview of [structured and unstructured formats](https://docs.redaction-technique.org/en/formats/structured-vs-unstructured-formats/), including the rationale for choosing DITA XML, see the dedicated article.

DITA XML is a structured authoring language that allows you to create documents without worrying about their final appearance on different media. XSL-FO is a language for reorganizing and filtering XML content and applying a style sheet layout to it.

A set of DITA XML files contains all the content related, for example, to a product. Various XSL-FO style sheets are used to publish this content in PDF, HTML, or other formats, applying complex transformations. The summary of each section of the final document may, for example, appear in the HTML version but not in the PDF version.

Similarly, if a product is to be supplied as a white label to different customers, a completely different layout can be applied to its documentation simply by specifying a different set of style sheets when generating the deliverable. In practice, this is not possible with traditional FrameMaker solutions.

## Choose a tutorial

Each tutorial stands alone: read only the one you need. Apart from the editor tutorials, they all assume a working DITA Open Toolkit installation, which the first group sets up.

Publish your first PDF
: [On GNU/Linux](#generate-a-pdf-with-dita-open-toolkit-under-gnulinux) or [on Windows](#generate-a-pdf-with-dita-open-toolkit-windows), with DITA-OT 4.4 and Java 17 or later. Start here if DITA-OT is not installed.

Create several documents from the same sources
: [Conditional text](#create-different-documents-from-the-same-dita-sources), written for DITA-OT 1.5.4, and [multilingual projects](#manage-multilingual-dita-xml-documentation-projects), with a Bash script for GNU/Linux.

Customize PDF output
: [Cross-references](#dita-open-toolkit-display-cross-references-in-pdfs) and [the index](#display-an-index-in-pdf), then two XSL-FO style sheet changes: [filter the content of examples](#xsl-fo-filter-content-according-to-except-and-or-conditions) and [insert a title before examples](#xsl-fo-automatically-insert-a-title-for-examples), the latter written for DITA-OT 1.7.

Edit DITA XML in Emacs
: [nXML mode](#use-the-nxml-ide-for-dita-xml) for validation and tag completion, with Emacs 23 or later, and [Predictive mode](#speed-up-your-typing-with-predictive-mode-for-emacs) for word completion. Independent of DITA-OT.

## Publish your first PDF

Set up the DITA Open Toolkit publishing chain and generate a sample PDF.

### Generate a PDF with DITA Open Toolkit under GNU/Linux

This DITA XML tutorial is designed to guide you through setting up and using the DITA-OT (DITA Open Toolkit) publishing chain in a GNU/Linux environment (Ubuntu or Debian).

**Prerequisites**

- Ubuntu or Debian on a physical or virtual machine with administrator access
- Java 17 or later (JDK)
- Internet connection

1. Download and unzip the DITA-OT (DITA Open Toolkit) archive:

    ```bash
    $ export REPO="https://github.com/dita-ot/dita-ot"
    $ wget $REPO/releases/download/4.4/dita-ot-4.4.zip
    $ unzip dita-ot-4.4.zip
    ```

2. Generate your first PDF:

    ```bash
    $ cd dita-ot-4.4
    $ bin/dita --input=samples/taskbook.ditamap --format=pdf
    ```

Congratulations, you've compiled your first DITA XML project! The PDF file generated is `out/taskbook.pdf`. You can now compile other projects by skipping steps 1 and 2.

### Generate a PDF with DITA Open Toolkit (Windows)

This DITA XML tutorial is designed to guide you through setting up and using the DITA-OT (DITA Open Toolkit) publishing chain on a current Windows installation.

**Prerequisites**

- Java 17 or later (JDK)
- Internet connection

1. Download Java, then run the installation program.

2. Download DITA Open Toolkit 4.4 (`dita-ot-4.4.zip`), then extract it, for example to your desktop.

3. Open the `Start` menu, type `cmd`, then press `Enter`. A terminal appears.

4. In the terminal, go to the extracted directory:

    ```bash
    cd Desktop\dita-ot-4.4
    ```

5. Generate your first PDF:

    ```bash
    bin\dita.bat --input=samples\taskbook.ditamap --format=pdf
    ```

    This command generates a PDF file from a sample DITA XML project.

    Congratulations, you've compiled your first DITA XML project! You'll find the target file in the `out` directory. You can now compile other projects by skipping steps 1 and 2.

## Create several documents from the same sources

Filter content by audience with conditional text, and generate each language version of a project.

### Create different documents from the same DITA sources

DITA XML offers a conditional text mechanism. This mechanism promotes the reuse of source content and avoids redundant information. This tutorial will help the technical writer use this mechanism in just a few minutes.

**Prerequisites**

- You have installed DITA-OT (DITA Open Toolkit) in the `DITA-OT1.5.4` directory under GNU/Linux or Windows.

1. Paste the following code into a file and save it as `conditional-text.dita` in the `DITA-OT1.5.4` directory:

    ```xml
    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE topic PUBLIC "-//OASIS//DTD DITA 1.2 Topic//EN"
    "/usr/share/dita-ot/dtd/technicalContent/dtd/topic.dtd">
    <topic id="example-topic" xml:lang="en-us">
      <title>Using Conditional Text</title>
      <body>
        <hazardstatement>
          <messagepanel audience="electricians">
            <typeofhazard>
              Danger for electricians
            </typeofhazard>
            <consequence>
              Risk of electrocution
            </consequence>
            <howtoavoid>
              Do not touch electrical wires.
            </howtoavoid>
          </messagepanel>
          <messagepanel audience="plumbers">
            <typeofhazard>
              Danger for plumbers
            </typeofhazard>
            <consequence>
              Risk of drowning
            </consequence>
            <howtoavoid>
              Do not dive into the pool.
            </howtoavoid>
          </messagepanel>
        </hazardstatement>
        <p>
         Any content placed between tags that does not include an
         <i>audience</i> value excluded in a file
         <i>.ditaval</i> is published in documents
         intended for plumbers and electricians.
      </p>
      </body>
    </topic>
    ```

    This code contains DITA XML tags containing different *audience* values: we'll exclude the contents of one of these two tags when generating the target file using the *audience* key.

2. Paste the following code into a file and save it as `conditional-text.ditamap` in the `DITA-OT1.5.4` directory:

    ```xml
    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE bookmap PUBLIC "-//OASIS//DTD DITA BookMap//EN"
    "/usr/share/dita-ot/dtd/bookmap/dtd/bookmap.dtd">
    <bookmap id="conditional-text">
      <booktitle>
        <mainbooktitle>
          Example of conditional text
        </mainbooktitle>
      </booktitle>
      <chapter href="conditional-text.dita"/>
    </bookmap>
    ```

3. Paste the following code into a file and save it as `electricians.ditaval` in the `DITA-OT1.5.4` directory:

    ```xml
    <?xml version="1.0" encoding="UTF-8"?>
    <val>
      <prop att="audience" val="electricians" action="include"/>
      <prop att="audience" val="plumbers" action="exclude"/>
    </val>
    ```

4. Paste the following code into a file and save it as `plumbers.ditaval` in the `DITA-OT1.5.4` directory:

    ```xml
    <?xml version="1.0" encoding="UTF-8"?>
    <val>
      <prop att="audience" val="electricians" action="exclude"/>
      <prop att="audience" val="plumbers" action="include"/>
    </val>
    ```

5. Open a terminal and enter the following command in the `DITA-OT1.5.4` directory:

    ```bash
    $ java -jar lib/dost.jar /i:conditional-text.ditamap \
    /filter:electricians.ditaval /outdir:. /transtype:pdf2
    ```

    Open the file `conditional-text.pdf`; it contains information for:

    - plumbers and electricians,
    - electricians only.

6. Open a terminal and enter the following command in the `DITA-OT1.5.4` directory:

    ```bash
    java -jar lib/dost.jar /i:conditional-text.ditamap \
    /filter:plumbers.ditaval /outdir:. /transtype:pdf2
    ```

    Open the file `conditional-text.pdf`; it contains information for:

    - plumbers and electricians,
    - plumbers only.

### Manage multilingual DITA XML documentation projects

DITA XML is a great format for managing documentation projects. For multilingual projects, however, the technical writer must create a ditamap file, which contains the table-of-contents structure of the documents, by version. This creates the risk of errors and inconsistencies. Fortunately, an appropriate methodology and an automation script for the DITA-OT (DITA Open Toolkit) publishing chain remedy this problem. The [modular document base](https://docs.redaction-technique.org/en/formats/modular-documentation/) article explains how DITA XML content is organized for multi-language reuse.

#### Methodology for multilingual DITA XML documentation projects

1. The ditamap file should not include a navtitle section, which contains a spelled-out title instead of extracting the title from the corresponding DITA XML section, and is therefore language-specific.

2. From the outset of your DITA XML project, place DITA XML content files in a subdirectory specific to the language in which they are initially written.

   For example:

   - product

     - en_US
       - images
       - tasks
       - topics

     and not:

   - product

     - images
     - tasks
     - topics

3. Replace all occurrences of the language-specific directory name in the ditamap file with a single temporary string.

   For example, use the string `@language-code@`:

   ```xml
   <topicref href="@language-code@/topics/managing-rights.dita"/>
   ```

   and not:

   ```xml
   <topicref href="en_US/topics/managing-rights.dita"/>
   ```

4. To generate the target files, you can now:

   a. Modify the `default.locale` parameter in the `demo/fo/build.xml` file.
   b. Replace the language variable in the ditamap file with the name of the language directory.
   c. Change the language parameter `xml:lang` in the ditamap file and in DITA XML content files.
   d. For PDF target files, modify page dimensions (A4 or US letter, for example) according to language.
   e. Generate target files.
   f. Restore initial values in source files.

Fortunately, a simple Bash script (GNU/Linux) can automate all this.

**Prerequisites**

- You have installed DITA-OT (DITA Open Toolkit).
- Your DITA XML project includes only one ditamap file.
- Your DITA XML content files have the extension `.dita`.
- The directory names of the language versions correspond to the language codes supported by Dita Open Toolkit (`fr_FR` or `en_US`, for example).
- Your DITA XML content files are located in subdirectories of the language version directories (for example, in `fr_FR/tasks/` and `fr_FR/topics/`).

Supported values for PDF page size are `fr_FR` (A4) and `en_US` (US letter). This script can of course be easily adapted or inspire a new script.

> **Caution: Warning**
>
> This script is supplied without warranty. Before running this script, make a backup of your entire DITA XML project, including configuration files (e.g. under a version control system). Make sure you can easily restore the entire project in the event of an error or unexpected behavior.

To use this script:

1. Download the multilingual DITA XML generation script into the directory containing the project ditamap file.

2. In a terminal, navigate to this directory and enter:

   ```bash
   $ chmod +x dita2target.sh
   ```

3. In the terminal, enter:

   ```bash
   $ mkdir out
   ```

   to create the directory containing the target files.

4. Enter:

   ```bash
   $ ./dita2target.sh <ditamap file> \
   <language directory name> <target format>
   ```

   to generate target files.

   The target format argument accepts values managed by DITA-OT (DITA Open Toolkit).

   **Example**

   ```bash
   ./dita2target.sh firewall.ditamap en_US pdf2
   ```

   The PDF file `firewall.pdf` is then generated in the `out` directory (hard-coded in the script).

## Customize PDF output

Adjust what DITA Open Toolkit puts in the PDF: first through its settings, then through XSL-FO templates.

### DITA Open Toolkit: Display cross-references in PDFs

> **Note**
>
> Cross-references are an important element of well-structured technical documentation. They enable the user to navigate easily through the building blocks and are a crucial element in the usability of the final document. DITA-OT (DITA Open Toolkit) handles them very well, provided a few adjustments are made.

You have placed correctly formatted *related-links* tags in your DITA XML content files, or better still, a reltable in your *ditamap* table of contents structure (the *reltable* allows you to decontextualize your content and therefore reuse it better). You launch your PDF generation command and, unpleasantly, no *Additional resources* section appears in the target file! You then try to generate an HTML version of your content and there, your *See also* section is indeed present. Wouldn't DITA-OT (DITA Open Toolkit) support cross-referencing in PDFs?

Fortunately, no. By default, cross-references are not generated in PDFs by DITA-OT (DITA Open Toolkit). To display them, assign the value *no* to the *disableRelatedLinks* variable in the `demo/fo/build_template.xml` file. If you use *ant*, you'll also need to pass the *args.fo.include.rellinks=all* parameter as follows:

```bash
ant -Dargs.input=samples/sequence.ditamap -Doutput.dir=out/ \
-Dtranstype=pdf2 -Dargs.fo.include.rellinks=all
```

### Display an Index in PDF

You've meticulously inserted your index entries into your DITA XML content files and you want them to appear in the generated PDF.

Historically, the Apache FOP processor bundled with DITA-OT (DITA Open Toolkit) did not support index generation, so displaying an index required a commercial FO processor (such as RenderX's XEP, used by proprietary tools like XMetaL) or one of several workarounds. This is no longer the case: index generation was reworked in DITA-OT 2.2 and the bundled Apache FOP now renders indexes directly. With a current DITA-OT (DITA Open Toolkit) release, the index entries you insert in your DITA XML content are included in the PDF output — no extra processor or workaround is required.

If you nonetheless choose not to display an index in the PDF, that remains a legitimate option: indexes are difficult to maintain and offer a questionable surplus of usability in a document that will only be consulted marginally in printed form. And for electronic formats, the absence of an index is more than compensated for by the full-text search function.

### XSL-FO: Filter content according to "except" and "or" conditions

Suppose you want to filter the child nodes of the DITA XML tag `<example>` and display all its content except the title (located between the `<title>` tags).

You can use the following syntax:

```xml
<xsl:template match="*[contains(@class,' topic/example ')]">
  <fo:block>
    <xsl:apply-templates select="*[not(name()='title')]" />
  </fo:block>
</xsl:template>
```

This command selects all child nodes of the `<example>` node, excluding the `<title>` node. However, the `<example>` node accepts text entered directly, without being encapsulated in tags. Therefore, this command will not display this content.

Suppose the source code of one of your DITA XML files is as follows:

```xml
<example>
  <title>
    XSL-FO
  </title>
  Here is my XPATH path example:
  <codeblock>
    ancestor-or-self
  </codeblock>
  Unencapsulated text located after a child node.
</example>
```

The PDF file will display the example structured as follows:

```xml
ancestor-or-self
```

The title of the example is not displayed, which is the desired result, but content not encapsulated in tags is not displayed, which is an undesirable side effect. To select this content, text nodes must be selected using the `text()` syntax. You may then be tempted to use the following syntax:

```xml
<xsl:template match="*[contains(@class,' topic/example ')]">
  <fo:block>
    <xsl:apply-templates select="text()" />
    <xsl:apply-templates select="*[not(name()='title')]" />
  </fo:block>
</xsl:template>
```

However, all text elements not encapsulated in child tags of the `<example>` tag will be placed at the beginning of the example, before the encapsulated elements, even if they are placed afterward in the DITA XML source file.

The PDF file will display the example structured as follows:

> Here's my XPATH path example: Unencapsulated text after a child node.
>
> ```xml
> ancestor-or-self
> ```

You must then use the pipe syntax (Boolean or condition) to modify the XPATH path as follows:

```xml
<xsl:apply-templates select="text()|*[not(name()='title')]" />
```

The final result will be:

```xml
<xsl:template match="*[contains(@class,' topic/example ')]">
  <fo:block>
    <xsl:apply-templates select="text()|*[not(name()='title')]" />
  </fo:block>
</xsl:template>
```

The PDF file will display the example structured as follows:

> Here is my XPATH path example:
>
> ```xml
> ancestor-or-self
> ```
>
> Unencapsulated text after a child node.

### XSL-FO: Automatically insert a title for examples

By default, DITA-OT (DITA Open Toolkit) does not automatically insert the text *Example:* before the title of an example contained between DITA XML tags `<example>`. However, XSL-FO syntax offers this possibility.

Suppose the source code of one of your DITA XML files is as follows:

```xml
<example>
  <title>
    XSL-FO
  </title>
  Here is my XPATH path example:
  <codeblock>
    ancestor-or-self
  </codeblock>
</example>
```

You want the generated PDF file to display the example structured as follows:

> **Example: XSL-FO**
>
> Here's my XPATH path example:
>
> ```xml
> ancestor-or-self
> ```

and if the example does not contain a title, it should be structured as follows:

> **Example:**
>
> Here's my XPATH path example:
>
> ```xml
> ancestor-or-self
> ```

By default, however, this content will be structured in the PDF by DITA-OT (DITA Open Toolkit) as:

> **XSL-FO**
>
> Here is my XPATH path example:
>
> ```xml
> ancestor-or-self
> ```

It's possible to enter text between `<example>` tags, but XSL-FO offers a more elegant and structured method.

#### Automatically insert a text variable before the title of examples

1. Replace in the `plugins/org.dita.pdf2/xsl/fo/commons.xsl` stylesheet (under DITA-OT (DITA Open Toolkit) 1.7.) the following template:

    ```xml
    <xsl:template match="*[contains(@class,' topic/example')]/*
    [contains(@class,' topic/title ')]">
      <fo:block xsl:use-attribute-sets="example.title">
        <xsl:call-template name="commonattributes"/>
        <xsl:apply-templates/>
      </fo:block>
    </xsl:template>
    ```

    with the following code:

    ```xml
    <xsl:template match="*[contains(@class,' topic/example ')]">
      <fo:block xsl:use-attribute-sets="example.title">
        <xsl:call-template name="insertVariable">
        <xsl:with-param name="theVariableID"
        select="'my-example-text'"/>
        </xsl:call-template>
        <xsl:apply-templates select="title"/>
      </fo:block>
      <fo:block>
      <xsl:apply-templates
      select="*[not(contains(@class, ' topic/title'))]
        |text()|processing-instruction()"/>
      </fo:block>
    </xsl:template>
    ```

2. Define in the files containing the language variables, such as `plugins/org.dita.pdf2/cfg/common/vars/en.xml`, the text variables to be inserted automatically, for example:

    ```xml
    <variable id="my-example-text">Example:</variable>
    ```

To achieve consistent behavior, you should disable this treatment for examples of specific *topics* types (*task*, in particular).

## Edit DITA XML in Emacs

Configure Emacs for DITA XML authoring. These tutorials do not require DITA Open Toolkit.

### Use the nXML IDE for DITA XML

The nXML mode offers real-time validation of XML documents (DocBook, XHTML, and others) and context-sensitive autocompletion of XML tags — no need to know the schema by heart. It has been built into Emacs core since Emacs 23, so there is nothing to install: any current Emacs already includes it. Out of the box, however, nXML mode doesn't know about DITA XML; this tutorial shows you how to enable it for DITA XML by associating the DITA RelaxNG schemas.

**Prerequisites**

- Emacs 23 or later (any current version; nXML mode is included)
- The directory structure of your DITA XML documentation project must be as follows:
  - language directory
    - concepts
    - faq
    - reference
    - tasks
    - topics

  where `<language directory>` has the value en_US, or fr_FR, etc.
- Command-line instructions are designed for GNU/Linux; they must be adapted for use in other environments.

1. Make a backup of your entire DITA XML documentation project.

2. nXML mode is already part of Emacs, so there is nothing to download or patch. It is the default mode for `.xml` files; to use it for DITA content files as well, tell Emacs to open `.dita` files in nXML mode by adding the following line to your `.emacs` (or `init.el`):

    ```lisp
    (add-to-list 'auto-mode-alist '("\\.dita\\'" . nxml-mode))
    ```

3. Download the RelaxNG schema archive for DITA XML into the root directory of your DITA XML documentation project.

4. Go to the root directory of your DITA XML documentation project, then paste the following command:

    ```bash
    $ tar xzvf rnc.tar.gz
    ```

    This command creates an `rnc` directory at the same level as the `<language directory>`.

5. Download the archive of schemas.xml files into the root directory of your DITA XML documentation project, then paste the command sequence below, replacing `<language directory>` with the appropriate value, such as en_US, or fr_FR. Repeat this step for all your language directories.

    ```bash
    $ export DIR="schemas.redaction-technique.org"
    $ tar xzvf $DIR.tar.gz && \
    cd <language directory> && \
    cp ../$DIR/concepts/schemas.xml concepts/ && \
    cp ../$DIR/faq/schemas.xml faq/ && \
    cp ../$DIR/reference/schemas.xml reference/ && \
    cp ../$DIR/tasks/schemas.xml tasks/ && \
    cp ../$DIR/topics/schemas.xml topics/ && \
    rm -rf ../$DIR/
    ```

    Your language directories should now contain the appropriate `schemas.xml` files:
    - en_US
      - concepts
        - schemas.xml
      - faq
        - schemas.xml
      - reference
        - schemas.xml
      - tasks
        - schemas.xml
      - topics
        - schemas.xml

    These `schemas.xml` files are nXML mode's schema-locating files: they tell nXML which RelaxNG schema to apply to each DITA topic type, which is what enables validation and tag completion. To associate a schema with the current buffer manually instead, use `C-c C-s C-f` (`rng-set-schema-file-name`).

6. Open a DITA XML content file (`.dita`) with Emacs. The DITA XML syntax is shown in color. Places where the schema is not respected are underlined in red.

7. To insert a new tag, enter `<`, then press Ctrl+Enter. The list of possible tags appears.

8. Select a tag, then press Enter. Press Ctrl+Enter to display the list of permitted attributes.

9. To insert a closing tag after text, enter `</`, then press Ctrl+Enter.

### Speed up your typing with Predictive mode for Emacs

This Predictive mode tutorial for Emacs is designed to help you set up and use Emacs' Predictive word autocompletion and editing mode in a GNU/Linux environment (in this case, Debian).

> **Note**
>
> The Predictive package appears to be unmaintained: its last release (version 0.24) dates from February 2013. The instructions below are kept for reference — check the tool's current status before investing time in it. For a lightweight, actively usable alternative, the package's own author suggests `pabbrev` mode.

1. Install make and texinfo:

    ```bash
    $ sudo apt install make texinfo
    ```

2. Download Predictive.

3. Unzip the Predictive archive:

    ```bash
    $ tar xzvf predictive-0.23.13.tar.gz
    ```

4. Go to the `predictive` directory:

    ```bash
    $ cd predictive
    ```

5. Compile predictive:

    ```bash
    $ make
    ```

6. Install predictive:

    ```bash
    $ sudo make install
    ```

7. Insert the following code in the `.emacs` file:

    ```lisp
    ;; predictive install location
         (add-to-list 'load-path "~/.emacs.d/predictive/")
         ;; dictionary locations
         (add-to-list 'load-path "~/.emacs.d/predictive/latex/")
         (add-to-list 'load-path "~/.emacs.d/predictive/texinfo/")
         (add-to-list 'load-path "~/.emacs.d/predictive/html/")
         ;; load predictive package
         (require 'predictive)
    ```

8. Start Emacs, then press Alt+X and enter:

    ```
    predictive-mode
    ```

## Related articles

- [Case study: NuFirewall documentation](https://docs.redaction-technique.org/en/formats/nufirewall-case-study/)
- [Case studies in using DITA XML](https://docs.redaction-technique.org/en/formats/dita-xml-case-studies/)
- [Formats and tools](https://docs.redaction-technique.org/en/costs/formats-and-tools/)

---

Source: https://docs.redaction-technique.org/en/tutorials/dita-xml-xsl-fo-tutorials/
