XSLT-like processing in CL
Wednesday, November 3, 2004
I frequently need to process XML documents. In the past, I've used
XSLT for this; however, XSLT is a pain to program in since
it is a verbose, XML-based language. Also, although XSLT is a very
powerful language for transforming XML documents, I find that I
usually use only a core subset of its features. Therefore, I've been using CL in place of XSLT for the
transformation-type XML processing that I do. XSLT lets you use a declarative approach if you
like; however, the more common usage pattern is functional and data-driven,
with different transformations occuring based on
the application of element-specific templates against the XML. It is this latter type of usage that I
decided to replicate in CL and I've written a very basic library to do
so.
The library is called XML-XFORM and it depends on the
XMLS XML parser
written by Miles Egan. XML-XFORM is
installable with
ASDF and has been tested with
ACL,
CLISP, and
LispWorks; however, it should work with any CL implementation that is
supported by XMLS. The exported symbols are:
- process-all-children: Given a node (XML element with any "child" elements or values), iterates through all the children. Similar in XSLT to <xsl:apply-templates/>.
- process-child: Given a node and an element name, iterates through all the child elements with that specific name. Similar in XSLT to <xsl:apply-templates select="foo"/>.
- process-node: Given a node, calls the specialized method that handles processing for that node.
- process-node-value: Generic function for handling XML element values. Similar to default element value handling and <xsl:value-of select="."/> in XSLT (but allows for greater control). There will normally only be a single process-node-value method.
- node-attr-value: Given an XML element attribute name and a node, returns the value of the attribute. Similar to "{foo}" in XSLT.
- node-xform: Generic function for performing transformations on specific elements. Similar to <xsl:template match="foo"> in XSLT. There will be a specialized method for each XML element name that has separate processing associated with it. An un-specialized method can be specified as a "catch-all" to handle default element processing.
- A DTD file, resume.dtd, that defines the structure of the XML resumé file. Having a DTD is convenient in that it allows me to use a standard XML editor (in my case, I use either Emacs or one of a number of different special-purpose products) to make certain that I create XML that is valid and that conforms to the structure that I expect to be processing. It also means that I don't need to put validation code in my CL program. (Note: XML-XFORM does not require that a DTD be used)
- The XML file, resume.xml, that contains all of my resumé data.
- A resume-html.asd ASDF file that builds and runs the example program.
- The resume-html.lisp file that does the transformation of the XML to HTML. The XSLT equivalent of this file is resume-html.xsl; however, the XSLT version only produces the short, tailored resumé and not the detailed version. (Note: the XSLT file is provided for comparison purposes only - neither it nor an XSLT processor are needed or used by XML-XFORM)
- Sample output of the program:
- With (xform): resume.html is my current resumé, tailored for my current position as a Software Architect.
- With (xform t): resume-detail.html is the detailed version of my resumé, including specifics of work done in each position as well as detail on non-work activities that I want to keep a record of.
- The complete package is downloadable in zip and tar.gz formats.

