changelog2x - Transform ChangeLogML files using XSLT stylesheets


    changelog2x --format html --css /styles/changelog.css < Changes.xml


This script is a simple example of transforming ChangeLogML mark-up into user-friendly formats. The application itself does very little work; it's purpose is mainly to process and handle the command-line options, then delegate the actual work to the App::Changelog2x (App::Changelog2x) module.

changelog2x installs with a set of sample XSLT stylesheets, as well as the XML Schema definition of ChangeLogML. These stylesheets allow conversion to valid XHTML (with comprehensive use of CSS classes for styling), a plain-text format based on typical ChangeLog files in use, and a variety of snippets useful for inclusion or embedding within other documents.


There are two distinct groups of options: application options that are used by changelog2x, and stylesheet options that are passed through to the XSLT processor for use/recognition by the processor itself. The latter group of options control such things as URLs for CSS, sorting order, etc.

Application Options

These options control the behavior of the application itself, and are not passed to the actual stylesheet processing:

--input FILE

If this option is passed, it specifies the ChangeLogML XML file to process. If the value of this string is -, or if the option is not passed at all, then the STDIN file-handle is used.

--output FILE

If this option is passed, it specifies the file to write the transformed content out to. If the value of this string is -, or if the option is not passed at all, then the STDOUT file-handle is used.

--format STRING

This option specifies an alternate format pattern for the DateTime strftime method to use when formatting the dates in the <release> tags. Note that DateTime->strftime formatting is sensitive to your locale setting. The format is also used for those output templates that include "generated on" comments.

This option may be abbreviated as -f for convenience.

--template NAME

Specifies the XSLT template to use. This may be a filename path or a string. A "string" is defined as a value consisting of only alphanumeric characters (those matching the Perl \w regular expression character class).

If the value of this parameter matches the pattern ^\w+$, then the string is used to construct a path to a XSLT file. The file is assumed to be named changelog2string.xslt, and is looked for in the directory declared as the root for templates (see the templateroot option, next).

If the parameter does not match the pattern, it is assumed to be a file name. If it is not an absolute path, it is looked for under the template root directory. As a special case, if the path starts with a . character, it is not converted to absolute.

Once the full path and name of the file has been determined, if it cannot be opened or read an error is reported.

This option may be abbreviated as -t for convenience. The default value of this option is html. See "Template Option Values" for the list of templates/stylesheets provided with the application, and what they produce.

--templateroot DIR
-tr DIR

Specifies an alternative root directory for locating the XSLT templates (stylesheets). By default, the root directory is a sub-directory called changelog2x in the same directory that the App::Changelog2x class-file is installed into. A directory specified with this option is added to the list of paths that get searched, so you can specify a directory that (for example) only provides a template for text, while still having the rest of templates be findable in the default directory.

If you do add a path, you can also take advantage of the expansion of "string" arguments to the template option (see above) into full file names, if you have files that fit that pattern in your chosen template directory.

This option may be abbreviated as -tr for convenience. It may be specified multiple times, with the search-order of the directories being the same order they're given on the command-line.

--headcontentfile FILE
--head FILE

This option allows the user to specify additional <head>-block content as the contents of a file, in lieu of the headcontent option below, under "Stylesheet Options". See the documentation of that option for more detail of its role. This option makes it easier to specify large and/or complex values that would otherwise be difficult or impossible to pass on a command-line.

If both this and headcontent are passed, this option takes precedence. If the file name specified cannot be opened or read, an error is reported.

This option may be abbreviated as --head for convenience.

--bodycontentfile FILE
--body FILE

This option allows the user to specify additional <body>-block content as the contents of a file, in lieu of the bodycontent option below, under "Stylesheet Options". See the documentation of that option for more detail of its role. This option makes it easier to specify large and/or complex values that would otherwise be difficult or impossible to pass on a command-line.

If both this and bodycontent are passed, this option takes precedence. If the file name specified cannot be opened or read, an error is reported.

This option may be abbreviated as --body for convenience.

Stylesheet Options

The following set of options are actually used by the XSLT processor (XML::LibXSLT in this case), and are not directly used by changelog2x at all. They are passed in to the transformation phase of the processing after being converted to XPath-style strings.

Some of the options only apply to certain of the stylesheets. This is denoted by listing the templates that the option affects in square brackets after the option-type.

--notoc (boolean) [ html ]

This is a boolean option. If given, it disables the generation of the shortcut-links at the top of the full-page XHTML rendition of the ChangeLogML file.

--versions STRING [ div, dl, html, text, ul ]

A string that specifies which release-versions should be processed. By default, all <release> blocks are processed. If this parameter is given, it acts as a sort of filter to limit the set of releases. The acceptable values for the string are:


This is the default value; all release blocks are processed in the sorted order.


If this value is given, then the first release block (based on sorting order) is processed and all others are ignored.


Generally, the value is assumed to be a comma-separated list of versions as defined by the version attribute of the <release> tag. As each release block is considered, if the version is present in the user-provided list then the release block is processed. There is (currently) no sort of wildcarding or regular-expression matching provided for the list.

Any string that is not first or all is assumed to be a list of versions. If it badly-formed, it will likely not match any of the release blocks, and none will be processed.

--order STRING [ div, dl, html, text, ul ]

This parameter should be a string whose value is one of ascending or descending. It controls the order in which the release blocks are sorted by their date attributes. The default is descending, which places the newest version at the top of the resulting document.

Date-sorting is used as proper sorting of version strings is usually problematic. Dates expressed in ISO 8601 will sort correctly when sorted as text. The only caveat is that two releases close to each other in different timezone-offsets could sort incorrectly, since the sorting would key off of the hours portion before taking the offsets into consideration. This is a limitation of XSL's sorting capabilities.

--class STRING [ htmlnewest, htmlversion ]

For the htmlnewest and htmlversion output templates, the overall XHTML content is much smaller than the other XHTML-oriented stylesheets. To this end, this option allows the user to specify an explicit CSS style-name to give to the containing elements that are generated. In the case of the htmlnewest stylesheet, this is a <div>. In the case of htmlversion, it is a <span>. See the documentation below ("Template Option Values") for the default class names for each of the templates.

--css URL [ html ]

Specifies a URL to be used as the basic CSS stylesheet when rendering a complete XHTML document. If given, a <link> element is created in the document's <head> section with the rel attribute set to stylesheet, the type attribute set to text/css and the href attribute set to the value of this parameter. No checking is done on the URL, and no constraints are applied. The URL may be absolute, relative, etc.

The only distinction between this parameter and the next one, is that this one will occur first in the <head> block, and thus be first in the CSS cascade model.

--color URL [ html ]

As above, but this parameter is used to allow a second URL to be specified, one that will follow the previous one in the CSS cascade order. This allows the user to have a "main" stylesheet with font, spacing, etc. declarations while also using this option to select between color schemes for text, backgrounds, etc. (hence the choice of color as the option name).

--javascript URL [ html ]

Like the two CSS-related options above, this allows the specification of a URL to be included in the document head-section. Unlike the previous, this URL is assumed to refer to a Javascript resource. As such, it triggers the generation of a <script> element with a type attribute set to text/javascript and a href attribute set to the value of this parameter.

This element occurs after any content specified in the headcontent (or appliction option headcontentfile) is included in the output. Thus, it can safely refer to any functions, etc. defined in that content.

--headcontent STRING [ html ]
--bodycontent STRING [ html ]

These options allow for the user to provide arbitrary content for the <head> and/or <body> sections of the XHTML document, when rendering a full document with the html template.

Realizing that the generalized stylesheets provided by this package won't fit every user's needs, these options are a sort of "wildcard" pass to include anything that can't be achieved by the existing stylesheet-targeted parameters. Note that as command-line arguments, they are limited as to how complex the values can be. Hence the headcontentfile and bodycontentfile options, which are handled by the application before processing is handed off to XML::LibXSLT. Also note that the file-oriented options to the application will override any values passed in via either of these options.

--xsltparam NAME=VALUE

Allow for the user to pass additional parameters to the XSLT processing phase beyond those defined here. If you have written your own XSLT stylesheets to use with the template and/or templateroot options, you may also have need for your own XSLT parameters. You may provide as many of these as you wish with this option. Each occurrence should have a value of the form, name=value, where name is the name the parameter will have when passed to the XSLT processor, and value will be the content of the parameter.

Template Option Values

This application installs with (at present) nine pre-defined stylesheets available for use. These are the potential values of the template option to the application (the default being html). The stylesheets fall into two groups: XHTML and plain-text.

XHTML templates

These templates produce content that is either complete, valid XHTML, or snippets that are conformant and should be easily included in larger documents:


This is the default stylesheet, which generates a complete XHTML document. The <body> tag and all its children will have a CSS classes associated with them that indicate the hierarchy to some extent, and allow for comprehensive styling via CSS.

The structure of the document is basically:

      headcontent parameter
      CSS parameters
      javascript parameter
      bodycontent parameter
      <h1> containing same text as <title>
      <div> containing abstract (top-most <description> block)
      ToC-style links
      <div> containing one or more release blocks:
        <div> wrapping one release:
          <span> containing subproject name (if release is from a subproject)
          <span> containing version number
          <span> containing release date
          <p> containing release-level <description>, if present
          <div> containing one or more change blocks:
            <div> wrapping one change:
              <span> containing transaction revision, if any
              <ul> containing one or more files:
                <li> containing one file, possibly with revision
                     and/or action information
              <p> containing the change-level <description>
      <div> containing diagnostics/credits data

This doesn't include most of the viewer-visible content that doesn't come directly from the input file (things like labels, etc.), except for the two horizontal-rule elements, which contribute to the overall visual structure. Every element referred to above (and some that are implied, but not explicitly listed) is given a CSS class name. See "CSS Class Hierarchy" for details on the class names and where they are used.


This stylesheet renders a structure similar to the above, except that it only produces the <div element that contains the release blocks. Referring to the structure above, this is the <div> that immediately follows the first <hr>. An XML comment is included with some information on the version of the stylesheet used, as well as tools. However, no visible content is included (i.e., no "footer" as follows the second <hr> in the layout above).


Like the previous stylesheet, this produces an XHTML fragment suitable for inclusion in a larger document. However, it differs in that the outermost container is not a <div>, but instead a <ul>. The containing <ul> is assigned a different CSS class than the <ul> containers used for change-blocks. Each release-block is rendered within one <li> child-element (which is also assigned a distinct class from the similar elements used within the change-blocks). This stylesheet also includes some diagnostic information as an XML/XHTML comment, but does not include it in any visible elements.


As with the previous two stylesheets, this produces an XHTML fragment for inclusion in other documents. In this case, the outermost container element is a <dl>. The structure of this template's output is also somewhat different: where the previous two rendered each release-block in the same manner as the whole-document stylesheet, this stylesheet moves the pseudo-heading line that contains the word "Version" followed by the release's version number into the <dt> element, and renders the remainder of the release block in the <dd> element. As with the others, the stylesheet also includes some diagnostic information as an XML/XHTML comment, but does not include it in any visible elements.


This is a special variation of the div stylesheet, that contains exactly one release-block, that of the most-recent release (as sorted by date). The outermost container is a <div> element whose CSS class dfaults to the same class used for the top-most container in the other templates. However, the user may specify a different CSS class with the class stylesheet parameter (see "Stylesheet Options"), if they wish to have this XHTML fragment adhere to styles defined in a different CSS stylesheet. Diagnostic information is included within a comment.


This is similar to the previous stylesheet, but only renders a single <span> tag containing the version-string of the newest release (as sorted by date). The element is assigned a CSS class whose name fits within the general naming scheme of other CSS classes used in these templates. As with the previous, the class can be specified by the user via the class parameter.

For all varieties of XHTML output, any elements in <description> blocks that belong to the namespace set aside by the W3C for XHTML ( are copied into the output verbatim, except that a class attribute is added to allow the user to include CSS style information with the rest of the changelog-related CSS declarations. If the element already has a class attribute, it is copied over and the new class name added at the end of the existing content. The new class name is created by appending the tag name to the string changelog-html-. Thus, an element p gets the class changelog-html-p. For example (assuming that the xhtml prefix has been declared to reference the XHTML namespace), the following content:

    <xhtml:a href=""></xhtml:a>

yields this output:

    <a href="" class="changelog-html-a"></a>

The following content (which already has a class attribute):

    <xhtml:span class="bold">Bold Span</xhtml:span>


    <span class="bold changelog-html-span">Bold Span</span>

No other foreign XML tags are copied over, at present. Allowance has been made for future extension with information such as version-control system specification, hosting information, Dublin Core metadata, etc.

Text templates

These templates produce plain-text output:


This template produces output that comes very close to the de-facto standard plain-text "Changelog" so familiar to open-source projects. After the project name and in-set description (formatted like a document abstract, left-justified and centered with regards to an 80-column page), the releases are presented in the sorted order (possibly filtered by the versions parameter).

Each release starts with a line like this:

    0.19    Monday October 20, 2008, 02:00:00 AM -0700

The version string is left-justified, followed by a single tab-stop character and the formatted date (see the format application option to control the formatting of the dates).

Following the "header" for a release, each <change> element is presented (in order) in a format roughly like this:

            [ <transaction-revision number> ]
            * FILE-1 [ <revision number> [, <action label> ] ]
            Change <description> text

If the change-block contains a <fileset> that itself has a revision attribute, the first line in the example above is produced, identifying this as the revision identifier for the transaction as a whole (similar to how systems like Subversion group commits of multiple files at once into a "transaction"). Then, all the files listed in the change are enumerated as a bulleted-list. For each file, if there is a revision attribute on the <file> element, it is displayed after the path. If the file has an action attribute, a parenthetical action-label is further appended. Once all files have been listed, the contents of the <description> element are displayed, indented 8 spaces and word-wrapped to a width of 70 columns.

At the end of the output, several lines are added with # in the first two columns (pseudo-comment notation) that identify the revision of the XSLT stylesheet used, the date/time when it was processed, and the tools used to do the processing.


This template is similar to the htmlnewest listed earlier, except that it generates plain-text. It outputs the newest revision as a single block, using the same format and layout as described above for text. However, it does not output the pseudo-comments at the end.


This template is the plain-text counterpart to htmlversion. It outputs just the version-string of the most-recent release. It does not output a newline character, so that the result of this can be saved to a file that can be later inserted into other files without bringing in a potentially-unwanted line-break. (As opposed to the output of the textnewest stylesheet, above, which ends in a fully-formatted paragraph for which an ending newline makes sense.)

All stylesheets that generate plain-text will strip XHTML elements out of the output while retaining the text content they have. Thus, a construct like the example used above:

    <xhtml:a href=""></xhtml:a>

will output as plain text simply:

Null elements such as <br /> or <p></p> will not add anything to the output.

As with the XHTML templates, XML tags that are not part of ChangeLogML or XHTML are removed completely. Their present is tolerated, however, to allow for future integration of additional metadata.

CSS Class Hierarchy

To illustrate the hierarchy of classes used to allow CSS styling, the diagram from earlier is revisited and revised:

    <body class="changelog">
      <h1 class="changelog-title" />
      <div class="changelog-abstract" />
      <div class="changelog-toc-div"> [*]
        <a class="changelog-toc-link" />
      <hr class="changelog-divider" />
      <div class="changelog-container-div">
        <div class="changelog-release-div">
          <span class="changelog-subproject-heading"> [*]
          <span class="changelog-release-heading">
          <a class="changelog-toc-link" /> (link back to top) [*]
          <span class="changelog-release-date">
            <span class="changelog-date" />
          <p class="changelog-release-para" /> [*]
          <div class="changelog-release-changes-container">
            <div class="changelog-release-change">
              <span class="changelog-transaction-revision" /> [*]
              <ul class="changelog-release-change-ul">
                <li class="changelog-release-change-li">
                  <tt class="changelog-filename" />
                  <span class="changelog-file-revision" /> [*]
                  <span class="changelog-release-file-action" /> [*]
              <p class="changelog-release-change-para" />
      <hr class="changelog-divider" />
      <div class="changelog-footer">
        <p class="changelog-credits">
          <span class="changelog-credits-revinfo" />
          <span class="changelog-credits-date" />
          <span class="changelog-credits-toolchain" />

Those elements marked with an asterisk (*) to their right side might not be present. In some cases (the table-of-contents), they may be opted-out by the user. In other cases they are only present if there is data to be contained (that is, empty container-tags are not rendered).

The file changelogml.css that comes with this distribution implements almost all of these classes, and can serve as a reference.


App::Changelog2x, XML::LibXSLT,


Randy J. Ray <>


Please report any bugs or feature requests to bug-app-changelog2x at, or through the web interface at I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.



This file and the code within are copyright (c) 2008 by Randy J. Ray.

Copying and distribution are permitted under the terms of the Artistic License 2.0 ( or the GNU LGPL 2.1 (