Skip to content

Case study: NuFirewall documentation

NuFirewall’s documentation, praised by the press as a notable strength of the product, was developed using DITA XML.

By adopting a format that maximizes information reuse, I was able to focus more on the content itself.

When a technical writer needs to reuse specific DITA XML information blocks smaller than a section, they should be shared within dita content files instead of ditamap table of contents structures, using the conref mechanism.

The conref principle is straightforward: when a conref is specified at a particular XML node, the content of the target node is replaced by the content of the source node.

Sharing of large information blocks between ditamaps Sharing of broad granularity information blocks between ditamaps

A key difference between the conref mechanism and the XML xinclude mechanism is that the source node must comply with the XSD schema of both the source and target files. This formal rigor, while sometimes less flexible, enhances conref readability compared to xinclude, thereby encouraging its use.

Sharing fine-grained information blocks between DITA XML sections Sharing of fine-grain information blocks between DITA XML sections

While initially easier to reuse content by referencing existing DITA XML files without extracting them, one core content reuse principle is decontextualization. Extracting and placing reused content into a dedicated conref source file ultimately proves more efficient. It’s easier to locate source elements in one repository than searching across numerous files.

Decentralized conref management is inefficient Managing conrefs in a decentralized way is inefficient.

Conrefs are resolved at compile time even if source files are not referenced in the ditamap file generating the deliverable. Thus, conref sources can reside in higher-level directories than the ditamap.

Good conref management Good conref management

Content files in ditamap structures contain only target conref values, while a central file consolidates all source conref values, potentially with internal references to certain target values.

This central file should be of the same type (task, concept, reference, etc.) as the content files or at least composite, accommodating all types of DITA XML structures. I find it efficient, for organizational purposes, to create a central file for each DITA XML topic type to share type-specific information, reserving the composite type for a general-purpose file with cross-topic-type shared information.

Ensure each source conref in a file has a unique ID, using explicit human-readable names to maintain clarity in dita files with target conrefs.

The technical writer should use the lowest-level DITA XML node containing the information to be shared as the conref source.

Given conref’s design for managing small information blocks, using the smallest XML structure encapsulating the information is logical, even if compatibility with the DITA XML section’s XSD schema necessitates inclusion in larger structures.

Conref placed on lowest-level XML node Placement on the lowest-level XML node.

For instance, to reuse “Click OK,” ensure your source conref file is structured as:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE task PUBLIC "-//OASIS//DTD DITA 1.2 Task//EN"
/usr/share/dita-ot/dtd/technicalContent/dtd/task.dtd">
<task id="shared" xml:lang="fr-fr">
<title>Conref source</title>
<taskbody>
<steps>
<step>
<cmd>
Click OK.
</cmd>
</step>
</steps>
</taskbody>

Assign an ID to the XML structure for reuse. It’s optimal to use:

<step>
<cmd id="click-ok">
Click OK.
</cmd>
</step>

instead of:

<step id="click-ok">
<cmd>
Click OK.
</cmd>
</step>

In the first method, conref usage is possible even if the top node (<step>) includes nodes beyond <step>, such as <info>.

Conref placed on highest-level XML node Placement on top-level XML node.

In the second scenario, the entire <step> node content is replaced by the source conref. Thus, the following code will omit node content in deliverables:

<step id="click-ok">
<cmd/>
<info>
If you can't read, this is the green button.
</info>
</step>

The smallest DITA XML information unit is the <ph> node. However, technical writers should apply the conref mechanism only for complete sentences or terms not intended for translation (e.g., company or product names). Otherwise, significant issues arise during language translation.

Sentence structure varies by language Sentence structure varies by language.

Example

If you set conref granularity at the segment level and define:

<ph id="click">Click the</ph>
<ph id="blue">blue</ph>
<ph id="arrow">arrow</ph>

You can then use:

<p>
<ph conref="shared.dita/click"/>
<ph conref="shared.dita/blue"/>
<ph conref="shared.dita/arrow"/>.
</p>

to generate “Click the blue arrow.”

To create a French version, you translate conrefs as:

<ph id="click">Click the</ph>
<ph id="blue">blue</ph>
<ph id="arrow">arrow</ph>

yielding “Click the blue arrow.”

To avoid issues, rearranging conref order in translated DITA XML files is impractical. Worse problems can lead to completely discarding conrefs in the target language (though I’ve avoided such pitfalls myself).

To facilitate DITA XML content maintenance and updates, technical writers should minimize excessive conref nesting. A single level (one conref within another) is generally manageable.

In the example below, source conref see-admin-guide includes target conref admin-guide-title:

Example

<p id="see-admin-guide">
For further information, see the <ph
conref="shared.dita/admin-guide-title"/>.
</p>

This complexity level is navigable. However, if admin-guide-title contains yet another target conref, the DITA XML becomes cumbersome (not to mention circular reference risks). In theory, conref combinations are infinite, but practical issues are vast!

Conref multi-level nesting: risky Multi-level conref nesting: risky!

Summary:

  • Multiple source conref nesting is viable but impacts file readability.
  • Source and target conref nesting is often unmanageable.
  • Target conref cannot nest; top-level conref overrules lower-level values.

Task sections, due to their nature, often see higher content reuse than concept or reference sections.

Conref modularizes small information blocks Conrefs modularize small information blocks.

Quickly producing files with only unique titles, while generating the remainder from conref, is common.

Example

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE task PUBLIC "-//OASIS//DTD DITA 1.2 Task//EN"
"/usr/share/dita-ot/dtd/technicalContent/dtd/task.dtd">
<task id="display-trends" xml:lang="fr-fr">
<title>Display trends</title>
<taskbody>
<context audience="basic">
<note type="restriction" audience="advanced">
<ul>
<li>
<ph conref="shared.dita/ip-control"/>
</li>
</ul>
<ph conref="../../shared/shared.dita/see-user-guide"
audience="no-user-guide"/>
</note>
</context>
<steps>
<step>
<cmd audience="basic">
<menucascade>
<uicontrol conref="shared.dita/logs"/>
</menucascade>
</cmd>
<choices audience="advanced">
<choice>
<ph conref="shared.dita/physical-appliance"/>
<menucascade>
<uicontrol conref="shared.dita/logs"/>
</menucascade>
</choice>
<choice>
<ph conref="shared.dita/virtual-appliance"/>
<menucascade>
<uicontrol conref="shared.dita/server"/>
<uicontrol conref="shared.dita/logs"/>
</menucascade>
</choice>
</choices>
</step>
<step>
<cmd>
<menucascade>
<uicontrol conref="shared.dita/all"/>
<uicontrol conref="shared.dita/editfile"/>
</menucascade>
</cmd>
<info>
<ul conref="shared.dita/drill-down">
<li/>
</ul>
<note conref="shared.dita/randomnames"/>
</info>
</step>
</steps>
</taskbody>
</task>

Only the text in black requires translation. Translating this type of DITA XML content involves translating just the title and the full set of source conref. Translators, lacking context for these discrete information units, require support. Ideally, translators work onsite, accessing both the technical writer and product designers.

You can also apply this to structural elements, like table headings, to present information consistently at lower costs without specialization.

Consider a scenario where a file with confidential information requires translation, but cannot be accessed by the translator (due to client confidentiality clauses).

What can be done? The ditaval mechanism filters out information from the deliverables but not from the source files. Must you create separate source files for confidential and non-confidential information? That negates single-sourcing and content reuse—the very reasons for choosing DITA XML!

Hide confidential information from translators Hide confidential information from translators

By placing confidential content in a separate file (e.g., confidential.dita) and setting conref with a filter key in the translatable file, you manage access. The translator processes only non-confidential text, and deliverables in the target language exclude confidential content, marked as conditional and explicitly excluded via the ditaval file during compilation.

Provide targeted information with Ditaval conditional text

Section titled “Provide targeted information with Ditaval conditional text”

A ditaval file operates like 3D glasses: one lens masks one half of the information, the other lens the other half. Only the technical writer has complete information.

The information recipients have glasses showing either only left or right lens content. Though they see less, they access what they need without noise. This adheres to the minimalist principle “less is more.”

Conditional text with DITA XML Conditional text with DITA XML

The ditaval mechanism is based on binary logic: mark a block with an attribute and value, then include or exclude it in deliverables via a compile-time operand (default is inclusion without operand). This constitutes conditional text.

This mechanism negates the need for separate files for minor content variations, further reducing source content redundancy.

Serial filter keys (condition and) can be specified using space-separated values in attributes like product, audience, etc.

Example

To profile information for both electricians and advanced users among these groups:

  • Non-electricians
  • Beginner electricians
  • Expert electricians

Use the structure:

<step audience="electricians advanced">
<cmd> Bring the intensity below the lethal dose of 150mA. </cmd>
</step>

Example

Correct before filtering:

<thead>
<row product="a">
<entry>Order</entry>
<entry>Description</entry>
</row>
</thead>

After filtering, the result is:

<thead>
</thead>

According to the XSD schema, table headers require at least one row:

<!ENTITY % thead.content "((%row;)+)">

This filtered code is incorrect and leads to compilation failure.