Tutorial time: creating Happy HTML

Imagine you want HTML5, but not … normal HTML5. You want … happy HTML5.

In this context, "happyhtml" means an HTML build process that wants you to be happy. It already knows what options you want. It knows that you pretty much always turn on draft output. It knows that you always use your own CSS file. And most importantly, it knows that your HTML5 output should smile.

To do this, we need to set up a plugin.

This plugin will do a few relatively simple things:

  1. Declare a new transform type, "happyhtml", and give the plugin an ID like org.metadita.happyhtml
  2. Provide the Ant code to run that build: set your default parameters, then do The Usual.
  3. Provide some XSL processing to cheer up your output.
  4. Bundle your CSS file.

org.metadita.happyhtml file organization

While sub-directories are not required, I'll use them here just because they make me happy. I'm only going to use 4 files: the plugin.xml file, my Ant build process for "happyhtml", my CSS file, and my XSL style override:
org.metadita.happyhtml\plugin.xml
org.metadita.happyhtml\happybuild.xml
org.metadita.happyhtml\css\myBrand.css
org.metadita.happyhtml\xsl\happyStyle.xsl

The plugin.xml file

This file is pretty straightforward, because in the end my plugin is pretty straightforward. It declares the "happyhtml" transform type, and then declares the Ant file that will define the build:

<?xml version="1.0" encoding="UTF-8"?>
<plugin id="org.metadita.happyhtml">
  <require plugin="org.dita.html5"/>
  <transtype name="happyhtml" extends="html5" desc="HappyHTML"/>
  <feature extension="dita.conductor.target.relative" file="happybuild.xml"/>
</plugin>

For a longer description of these extensions points (as well as the doc for every other extension point), see the DITA-OT developer documentation.

Setting up the "transform type"

To create a transform type of "happyhtml", we need to define an Ant target named dita2happyhtml. To meet our objectives, this should first call a new target to initialize default parameters, and then call the normal HTML5 process. (For background, there's an additional topic in the documentation that explains the dita2happyhtml naming convention.)

To keep this (relatively) simple, I'll only set a few default parameters: turn on draft output, provide the default CSS and copy it, and set up the XSL I want to run. I could of course set a default for every HTML5 parameter, but that seems … excessive.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:dita="http://dita-ot.sourceforge.net" name="dita2happyhtml">

  <!-- Define "happyhtml": first set params in an initialization step, then call dita2html5 -->
  <target name="dita2happyhtml" depends="happyhtml.init, dita2html5"/>

  <!-- Remember: ${dita.plugin.org.metadita.happyhtml.dir} is a generated variable
       that makes use of this plugin's ID to find its directory. -->
  <target name="happyhtml.init">
    <property name="args.draft" value="yes"/>
    <property name="args.css" value="${dita.plugin.org.metadita.happyhtml.dir}/css/myBrand.css"/>
    <property name="args.copycss" value="yes"/>
    <property name="args.xsl" value="${dita.plugin.org.metadita.happyhtml.dir}/xsl/happyStyle.xsl"/>
  </target>

</project>
Note: If I (or somebody I share this with) decide to create Happy HTML without draft content, all I need to do is set the draft parameter to "no" when I call this build, the same way most builds would set it to "yes". One advantage to this approach, where I use the @depends attribute to initialize defaults and then run dita2html5, is that any of my defaults can still be set to other values with the command line.

Creating a happy style

Now, I need a style override that (as promised) makes my HTML happy. So … what could possibly do that?

Obviously, emojis. So, I've set up my override to replace every space in a title with the ☺ character.

And because this is (obviously) a bit tongue in cheek, I've also replaced every space in a list item with 😜.

Of course, it also needs to import all of the normal HTML5 processing rules. So the complete override is an <xsl:import> to pull in normal processing, followed by an override for text anywhere in a title, and finally an override for non-empty text anywhere in a list item:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="2.0">

  <xsl:import href="plugin:org.dita.html5:xsl/dita2html5.xsl"/>

  <xsl:template match="*[contains(@class,' topic/title ')]//text()">
    <xsl:value-of select="translate(.,' ','☺')"/>
  </xsl:template>  
  
  <xsl:template match="*[contains(@class,' topic/li ')]//text()[normalize-space()]">
    <xsl:value-of select="translate(.,' ','&#x1F61C;')"/>
  </xsl:template>

</xsl:stylesheet>

Adding a cascading bit o' style

I expect that while many might want to customize their HTML with an XSLT override, CSS overrides are more common. So I've created a simple myBrand.css that becomes a part of every build; I don't have to remember it, because the happyhtml transform type references the standard copy in the plugin, and ensures it's copied with the output.

My CSS in this sample doesn't do much beyond setting a default font. And while I can't say I've ever found Comic Sans funny, it … seems strangely appropriate here.

body { color: black; 
       background-color: white;
       font-family: "Comic Sans MS", Arial, Helvetica, sans-serif;
       font-size: 90%; }
Tip: If all you really want to do is bundle your CSS in a plugin, there's a much less verbose transtype tutorial in the DITA-OT documentation.

What's left

With these four files – plugin.xml, an Ant file, XSLT, and CSS – I have a very happy plugin. All that's left is to place it in the DITA-OT plugin directory and install it. To do that, I need to place the org.metadita.happyhtml directory under DITA-OT/plugins/ to create DITA-OT/plugins/org.metadita.happyhtml.

To install, after placing the plugin in that location, run this command from the DITA-OT base directory:

bin/dita -install
Tip: If you want to install my sample copy directly from the web instead of making them yourself, you could run the following command instead:
bin/dita -install=http://metadita.org/toolkit/org.metadita.happyhtml.zip

Now, to try it out on some sample files, run:

bin/dita -i docsrc/samples/hierarchy.ditamap -f happyhtml -o out

This will build the age-old garage samples to the new happyhtml format. Open up out/tasks/changingtheoil.html, and you should be … very happy.

Conclusions and next steps

I suspect that this exact plugin doesn't quite meet your needs. But realistically, your needs probably differ from most other companies, so why not create your own "myHTML" transform type?

Begin by either following the steps above, or just downloading the "happyhtml" transform and start hacking:

  1. You'll probably want to rename the plugin to something that fits your environment. Remember to change the plugin ID in plugin.xml to match.
  2. If you're building with the command line today and always setting the same options – replace my args.draft example with the value(s) you need.
  3. If you want your own CSS - that's even easier, just replace the myBrand.css file and update the args.css parameter. Remember to change the directory variable to match your new plugin ID.
  4. If you want to dig into XSLT to override styles, you've already got a sample set up to start with. If not, just delete the args.xsl line from the Ant build.

And with that … happy building!

[EDIT 8 February 2017] Up next...

If you enjoyed making Happy HTML, you might also enjoy "Moody HTML for variable content". In that follow-up tutorial we use a plugin to create a new command line parameter and then use it to generate HTML with a wide variety of selectable moods. Enjoy!