Computers were first invented to do math, and they do it really well. But it didn't take long for users to repurpose their futuristic calculators into fancy, dynamic typewriters. Now human-readable text drives computing, so it's important to choose the right format for the text you write.
DocBook is an XML schema. XML is an extensible markup language a lot like HTML. It's truly ubiquitous, but you may know it by RSS or Atom, the Open Document formats of LibreOffice and Apache OpenOffice, Inkscape and the SVG file format, and much more. In fact, it's safe to say that if you own a computer or mobile device, there's XML on it.
This is what it looks like in its raw form:
<chapter>
<title>My title goes here</title>
<para>
Paragraph text goes here.
</para>
<section>
<title>A section title</title>
<para>
More paragraph text. Some in <emphasis>italics</emphasis>.
</para>
</section>
</chapter>
DocBook itself is easy to learn and easy to write, and it's also one of the most flexible formats available. What other formats, like Markdown and reStructured Text lack, DocBook provides. And what DocBook doesn't provide is possible through generic XML.
But why bother learning DocBook in a time when simpler alternatives exist? Why bother with a markup language at all when you can instead impose a little structure to your otherwise plain text and end up with highly portable, computer- and human-readable data?
Settle in. All will be revealed.
Fail faster
A distinct difference between working in simpler formats and working in DocBook is that DocBook tells you when you get something wrong. Many other formats, like Markdown and HTML, fail silently. And usually that feels good, because the result is that your document is rendered. You press the Enter key and your document gets processed by whatever parser or processor it requires for conversion, and you're done. What a great feeling.
The reality of failing silently, though, is that it still failed. You might have gotten output, and most of it might look just fine, but what about the error that wasn't caught? Maybe it renders something incorrectly, but if it's buried in page 42 of a 200-page document, when will you notice? Maybe the error rendered correctly in the web version of your document, but incorrectly for the print version.DocBook, like all XML, is famously strict. If you, for instance, place a <para> after you've closed your <chapter>, then your document build fails, and it generally fails verbosely. Because DocBook is XML, you can even run your source through xmllint to find errors early.
Experiencing errors is never easy. It's not fun to watch your work fizzle out in a pool of illegal tags and syntax errors instead of building into a beautifully rendered EPUB, webpage, or PDF. To get around that disappointment, most processors accept an option to temporarily ignore errors, such as --skip-validation, but ultimately failure is important. Failure identifies imperfections in your source and protects you from unpleasant surprises in your product.
Easier than it looks
DocBook sometimes has a reputation for being hard to learn. I have found that more often it's not DocBook, but the unique tool chains people build around it, that have the steep learning curve.
Compared to HTML, DocBook's tags are self-describing. Do you want to write an article or a book? Start with either the <article> or <book> tag, respectively. Start a new chapter in a book or a new section in an article with <chapter> or <section>, respectively. Start a paragraph with <para>, an ordered list with <orderedlist>, enter a list item with <listitem>, and so on.
Compared to Markdown and AsciiDoc, DocBook appears complex, but if you consider all the rules that aren't intuitive in structured text, DocBook's rules don't seem so bad.
Learning syntax from the original Markdown spec was often a process of trial and error, followed by a series of desperate internet searches, which meant wading through all the different Markdown flavors and parsers for the best applicable candidate for a correct answer. CommonMark, a project dedicated to defining a more arduous and strict specification, has helped, but users are often lulled into a false sense of security by how easy it is to learn the basics, only to find that achieving advanced results introduces a surprise learning curve.
Luckily, Markdown accepts HTML as a fallback markup option, and there are several tools and Markdown variants out there to make up for what the original spec lacks. Even so, if you're writing complex documents for several different output targets, it may not be as easy as it looks in all the "learn Markdown in just 15 minute"-style blogs.
The logic flow to learn something new in DocBook tends to be consistently simple:
- Go to the DocBook site.
- Find an appropriate tag in the master list.
- Refer to the tag's documentation to find out how to correctly use it.
That's all there is to it. It's about the same as learning HTML: learn the basics in the first few minutes, and keep a reference handy to learn more as needed.
Depending on how much you know about XML, there can be a few surprises, but the DocBook website clearly defines valid parent and child relationships for each and every tag, and each entry for each tag provides big blocks of examples.
Semantics
Finally, DocBook is important because it provides data about your data. DocBook tags aren't meant to dictate a style over your content, but to classify the information you are trying to convey. Like HTML and CSS, styling DocBook comes later, and it's completely malleable. DocBook tags provide semantic meaning to your words.
Semantics might not seem that important to you now, but here are two great examples of times that metadata became truly important in the real world:
- Before mobile phones existed, nobody on the internet would have ever thought that a telephone number would ever need a <tel> tag. If anything, surely an <em> or a <strong> tag would do. And then mobile phones happened, and people all over the world were browsing the internet on the same device they used to make phone calls, and it was a downright inconvenience not to be able to look up a company's phone number and click on it to make the call.
- A major phone company in New Zealand had been called Telecom for years. When it rebranded as Spark, the word telecommunication appeared as sparkmunication throughout its entire online documentation due to a find/replace mistake. The glitch was live on its website for several days before the obvious error was noticed and corrected. Better regex would have helped, but it wouldn't have happened at all with DocBook entities or the <trademark> tag.
Classifying the information you write is important now and as technology develops.
Create your first DocBook document the easy way
Here's a quick and easy way to get started with DocBook. This method emphasizes learning DocBook tags and syntax rather than building a complex and flexible tool chain.
- Open a text editor. Use whatever text editor you are most comfortable with, as long as it can save plain text files. All the good ones do: Gedit, Geany, Kate, Nano, Jove, Emacs, Atom, and many others.
- Open a web browser to DocBook 5.2: The Definitive Guide for reference.
- Open another tab in your web browser to the article element reference and scroll to the bottom of the page. Copy the text in the example box and paste it into your text editor.
- Use the example text as a template and write something. Some of that example's header is more verbose than you probably need, so here I've trimmed off some of the excess.
<article xmlns='http://docbook.org/ns/docbook'> <info> <title>My first docbook document</title> <author><personname> <firstname>Seth</firstname> <surname>Kenlon</surname> </personname></author> <publisher><publishername>opensource.com</publishername></publisher> <pubdate>2017</pubdate> </info> <section id="intro"> <title>Introduction</title> <para>Introductory text goes here.</para> </section> <section id="body"> <title>Section with a title</title> <para>Main body text goes here.</para> </section> <section id="conclusion"> <title>Conclusion</title> <para>Exciting and inspiring conclusion goes here.</para> </section> </article>
If you are ever in doubt about whether or not a tag is required, just refer to the tag's documentation. The synopsis section tells you what is required and what is optional. For example, the <section> element specifies that one or more title-related elements are required, but all other tags are optional.
- Once you've finished writing, it's time to render your document. There are several XML processors available, but the easiest for beginners is Pandoc. It's one of those "Swiss Army knife" applications that converts almost any kind of text into almost any other kind of text. What makes it especially nice for DocBook is that it has attractive stylesheets by default, while most other processors render very generic output under the assumption that you intend to apply your own XSL stylesheet.
There are all kinds of potential targets, but the commands are all basically the same:
$ pandoc --from docbook --to epub3 --output myDocbook.epub myDocbook.xml $ pandoc --from docbook --to markdown --output myDocbook.md myDocbook.xml $ pandoc --from docbook --to html --output myDocbook.html myDocbook.xml $ pandoc --from docbook --to latex --output myDocbook.pdf myDocbook.xml
And that's all there is to it. The more you write in DocBook, the more tags and attributes you learn, and eventually you'll probably find it hard to go back to a less explicit format.
Advanced DocBook, with style
Pandoc makes DocBook as easy as HTML, but XML is flexible, so if you need to, you can customize how you build your DocBook documents.
The default DocBook render from most processors (aside from Pandoc) looks a little something like this:
It's professional, but painfully so. Still, it's an important foundation upon which additional styles can be applied.
HTML and EPUB output
If your target involves HTML, you can continue to use Pandoc, instructing it to use your custom CSS.
$ pandoc --from docbook --to html \
--css=myStyle.css \
--output myDocbook.html myDocbook.xml
$ pandoc --from docbook --to epub3 \
--epub-stylesheet=myStyle.css --epub-cover-image=cover.jpg \
--epub-embed-font=fonts/foo.ttf --epub-embed-font=fonts/bar.ttf \
--output myDocbook.epub myDocbook.xml
The end result is dynamic, lightweight, modern, and as attractive as you make it.
PDF and print output
Rendering to PDF for digital distribution or printing relies either on LaTeX or XSL. I have yet to learn LaTeX, so I choose XSL, but if you're a LaTeX user, you can use Pandoc with custom templates. Otherwise, here's a brief introduction to XSL and the xsltproc command.
XSL is the eXtensible Stylesheet Language and is the CSS of the XML world. If you install DocBook from your Linux distribution or from the DocBook website, you are installing all the default DocBook stylesheets. These serve as the fallback styles whenever you use a tool like xsltproc or xmlto.
If you cannot (or choose not to) install DocBook, you can point to the stylesheets manually in your xsltproc command.
Building a PDF with xsltproc is a two-step process. First, you must generate the .fo file, which is a combination of your XML and your XSL, translated into XSL-FO (formatting objects) markup. Then you process the .fo file with Apache FOP, a Java application that converts formatting objects to PDF.
$ xsltproc --output tmp.fo myDocbook.xml
$ fop tmp.fo myDocbook.pdf
An easy modification to make when just getting started with styling DocBook is your font choice. Fonts are easy to change and make a noticeable difference in your end product.
- The first step in adding to the default style is editing an external stylesheet. For font detection, Then create a file called fonts.xml and enter this text:
<fop version="2.0"> <renderers> <renderer mime="application/pdf"> <fonts> <directory recursive="true">/absolute/path/to/your/system/fonts</directory> <auto-detect/> </fonts> </renderer> </renderers> </fop>
This registers all the TTF fonts in your personal or system fonts directory. You don't have to point it to standard font directories, but it must be an absolute, not relative, path.
- The next step when modifying a style is to set your new style option so that your processor knows what it is. There are two ways to make a change to XSL parameters. You can set a parameter dynamically as part of your xsltproc command, or you can make the change in an additional stylesheet.
I use both methods, depending on the gravity of the change. For simple styles that I change often, like page size (sometimes I need A4, other times US Letter), fonts, and so on, I pass parameters as part of my command. That way I can change them quickly and easily and independently of my custom stylesheets. To set fonts:
$ xsltproc --string-param body.font.family "League Gothic" \ --output tmp.fo \ myDocbook.xml
A list of valid parameters can be found at DocBook XSL Stylesheets User Reference: Parameters.
- To output to PDF, tell FOP to register your fonts with your fonts.xml file:
$ fop -c fonts.xml tmp.fo myDocbook.pdf
XSL stylesheet
For styles less likely to change based on printer requirements, page size, or mood, I place rules in a custom XSL template. XSL templates can get very complex, so making minor adjustments and learning over time is a good approach.
Here's a simple example.
A common visual cue seen in printed books is an admonition, like a note, tip, or warning, printed over a background color to let the reader know it is separate from the current narrative but still important to the topic. Admonitions are distinct elements in DocBook, so they're relatively simple to style.
The process is similar to styling fonts.
First, create a new file called mystyle.xsl in your working directory. Edit it so that it contains this heading:
<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:import href="https://opensource.com/usr/share/xml/docbook/xsl-stylesheets-1.78.1/fo/docbook.xsl"/>
The xsl:import line must point to the stylesheet on your system, whether you have installed it or you are using it from a nonstandard location in your home directory.
In this same file, enter some style rules:
<xsl:template match="note">
<xsl:variable name="id">
<xsl:call-template name="object.id"/>
</xsl:variable>
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format"
space-before.minimum="0.8em"
space-before.optimum="1em"
space-before.maximum="1.2em"
start-indent="0.25in"
end-indent="0.25in"
padding-top="6pt"
padding-bottom="2pt"
padding-left="4pt"
padding-right="4pt"
background-color="#ffffbd">
<xsl:if test="$admon.textlabel != 0 or title">
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format"
keep-with-next='always'
xsl:use-attribute-sets="admonition.title.properties"
font-family="League Script Thin"
color="#348fdf"
font-weight="bold">
<xsl:apply-templates select="." mode="object.title.markup"/>
</fo:block>
</xsl:if>
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format"
xsl:use-attribute-sets="admonition.properties"
font-family="League Gothic">
<xsl:apply-templates/>
</fo:block>
</fo:block>
</xsl:template>
</xsl:stylesheet>
This creates a template in your stylesheet for all elements that match the note. Whenever the XSL processor finds a <note> tag, it drops in the XSL-FO blocks to describe how elements are to be printed (whether the paper is digital or physical).
Apply the styles with xsltproc and output to PDF to FOP:
$ xsltproc --string-param body.font.family "League Gothic" \
mystyle.xsl --output tmp.fo \
myDocbook.xml
$ fop -c fonts.xml tmp.fo myDocbook.pdf
Get the output:
The syntax is nowhere as terse or simple as CSS syntax. However, simple styles follow the same format:
- Create an <xsl:template> block for the tag that you want to affect.
- Look up the available XSL attributes at DocBook XSL Stylesheets User Reference.
- Set the attributes you want to apply in a <fo:block>.
Like CSS, getting to know all your options takes time and practice, but once you get the hang of it, it's simple. More complex XML gets you more complex rules with dependencies, variables, conditionals, and more. For an exhaustive overview, see the definitive DocBook XSL: The Complete Guide website.
Using DocBook
DocBook was invented for tech writers, and many of its tags reflect that. However, I use DocBook for everything, whether it's tech writing, fiction, or RPG design, it's a powerful, industry-strength system.
This doesn't mean that there's no place in the world for Markdown or org-mode or other text formats. If I'm writing a README file or a short note to myself, DocBook is overkill, because the source document is also meant to be the final delivery format. In other words, where I would historically have used plain text, I use Markdown because Markdown's structure is a vast improvement over unstructured text.
I also use Markdown as an intermediate format. I usually write Opensource.com articles in DocBook and then output to Markdown so that a site editor can easily review and convert my work. Going directly from DocBook to HTML is great if you're running your own site and can govern what tags, classes, and IDs get used, but Markdown serves as an excellent intermediate step when you temporarily want to ignore your source metadata and just deliver the written words.
For everything else, DocBook is a great solution. Give it a try, and you'll never look at word processors, text, or XML the same way again.
9 Comments