Using XSLTUnit with XSLT 2.0

The latest version of XSLTUnit (v0.2) is from January 2002 and people sometimes ask me if the project is dead and when XSLTUnit will support XSLT 2.0.

The short answer is that you can already use XSLTUnit with XSLT 2.0.

The project is not dead and if I haven’t published any new version it’s just because XSLTUnit meets my needs and nobody has ever asked me any update.

I use it a lot and, no later than this afternoon, came on a new opportunity to use it to add unit tests to a function that I needed to debug for the Owark project.

Following ideas to develop a web service to create page archives, I was writing an XSLT transformation that analyses Heritrix crawl logs to determine what needs to be packaged into the archives and one of the touchy functions is to create user friendly local names that remains unique within the scope of an archive.

My first naive attempt didn’t survive real world tests and results were rather disappointing.

Using these results as a test suite was an obvious idea…

To do so, I have used log.xml, a real crawl log converted to XML as my source document and local-names.xml, the result of the transformation, as a reference.

The XSLTUnit transformation that exploit these documents, local-names.xsl, is very simple and is a nice example of what you can do with this framework and how you can use it with XSLT 2.0.

An XSLTUnit test suite is an XSLT transformation that imports both the transformation to test and xsltunit.xsl:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common" extension-element-prefixes="exsl" xmlns:xsltu="http://xsltunit.org/0/"
  xmlns:owk="http://owark.org/xslt/" exclude-result-prefixes="exsl">
  <xsl:import href="../actions/resource-index.xslt"/>
  <xsl:import href="xsltunit.xsl"/>

.../...

</xsl:stylesheet>

Here, the test suite and the XSLT transformation to test are both XSLT 2.0 and with Saxon they just work fine with xsltunit.xsl which is XSLT 1.0.

A XSLTUnit test case is composed of comparisons, and a test case to test that the value of the owk:local-name() function on a specific log entry is equal to “index.xml” could be:

      <xsltu:test id="index">
        <xsl:call-template name="xsltu:assertEqual">
          <xsl:with-param name="id" select="'index'"/>
          <xsl:with-param name="nodes1">
            <name>
              <xsl:value-of select="owk:local-name(/log/entry[uri='http://eric.van-der-vlist.com/blog/'])"/>
            </name>
          </xsl:with-param>
          <xsl:with-param name="nodes2">
            <name>index.html</name>
          </xsl:with-param>
        </xsl:call-template>
      </xsltu:test>

This crawl log includes 292 resources and you wouldn’t want to copy and past 291 times this snippet… No problem, you can just use some XSLT power and write:

 <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common" extension-element-prefixes="exsl" xmlns:xsltu="http://xsltunit.org/0/"
  xmlns:owk="http://owark.org/xslt/" exclude-result-prefixes="exsl">
  <xsl:import href="../actions/resource-index.xslt"/>
  <xsl:import href="xsltunit.xsl"/>
  <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
  <xsl:variable name="local-names" select="doc('local-names.xml')/index"/>
  <xsl:key name="log-by-uri" match="/log/entry" use="uri"/>
  <xsl:template match="/">
    <xsltu:tests>
      <xsl:for-each select="$local-names/resource">
        <xsltu:test id="{uri}">
          <xsl:call-template name="xsltu:assertEqual">
            <xsl:with-param name="id" select="uri"/>
            <xsl:with-param name="nodes1">
              <local-name>
                <xsl:value-of select="owk:unique-local-name(key('log-by-uri', current()/uri, $source ))"/>
              </local-name>
            </xsl:with-param>
            <xsl:with-param name="nodes2">
              <xsl:copy-of select="local-name"/>
            </xsl:with-param>
          </xsl:call-template>
        </xsltu:test>
      </xsl:for-each>
    </xsltu:tests>
  </xsl:template>
</xsl:stylesheet>

When you’ve done so, you can edit “local-names.xml” that contains the expected values so that they look more like what you want to, run the test suite to detect the differences, update your transformation accordingly and iterate.

Share and Enjoy:
  • Identi.ca
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Twitter
  • Add to favorites

Leave a Reply

Your email address will not be published. Required fields are marked *

Enter your OpenID as your website to log and skip name and email validation and moderation!