I’m currently reworking the process of how software documentation is produced. At the moment of writing we have many manual steps involved updating Microsoft Word document and finally exporting it to the portable document format (PDF). One of the steps is to copy a list of events including their identifiers, category, level and message, from an XML source to a Table in the word document.

The new process will allow to have source code management compatible plain text files as a source, from which a PDF is generated.

Of course I want to have the events step automated as well. So here is a XSLT (Extensible Stylesheet Language Transformations) that generates a Markdown table.

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output
    method="text"
    version="1.0"
    encoding="utf-8"
    omit-xml-declaration="yes"
    standalone="yes"
    indent="yes"
    media-type="plain/text" />
  <xsl:template match="//messages">
## Application Event Log Messages

| Id  | Category | Level | Message |
| --- | -------- | ----- | ------- |
<xsl:for-each select="add"><xsl:sort select="format-number(@id, '00000')" order="ascending" />
| <xsl:value-of select="@id"/> | <xsl:value-of select="@category"/> | <xsl:value-of select="@level"/> | <xsl:for-each select="en"><xsl:value-of select="text()"/></xsl:for-each> |</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

This can be called for instance by a PowerShell:

# Load the input file
$messageFilePath = "$PSScriptRoot/EventLogMessages.mcx";
$inputXml =
  [System.IO.File]::ReadAllText($messageFilePath);
$xml = New-Object System.Xml.XmlDocument;
$xml.XmlResolver = $null;
$xml.LoadXml($inputXml);
$messagesNode = $xml.SelectSingleNode("//messages");

# Load the transformation
$transformXsl =
  [System.IO.File]::ReadAllText("$PSScriptRoot/EventLogMessages.xslt");
$xsltProcessor = New-Object System.Xml.Xsl.XslCompiledTransform;
$sr = New-Object System.IO.StringReader($transformXsl);
$xr = [System.Xml.XmlReader]::Create($sr);
$xsltProcessor.Load($xr);
$xr.Dispose();
$sr.Dispose();

# Transform the input and write the output to a file
$sr = New-Object System.IO.StringReader($xml.OuterXml);
$xr = [System.Xml.XmlReader]::Create($sr);
$sw = New-Object System.IO.StringWriter;
$xsltProcessor.Transform($xr, $null, $sw);
$sw.ToString() | `
  Out-File -Encoding "utf8" -FilePath "$PSScriptRoot/EventLogMessages.md";
$sw.Dispose();
$xr.Dispose();
$sr.Dispose();

No more hands on the documentation, except you really want to write documentation.