Xslt Exercise

Gw

The goal of this exercise is to make yourself familiar with XSLT, which many of you will be using heavily in the GW project. We give you a few sample exercises, but encourage you to try out what happens if you change the input or the required presentation.

For XSLT resources, see the technical documentation for GW. Just pick one of the tutorials, depending on how much you already know about XML and XSLT. The XPath service listed in the XPath section is very useful to learn how to use XPath.

If this is your first time on a Linux machine at the UU, then you might find the tips in user friendly linux useful to read first.

Applying an XSL Transformation

First, let's make sure that you know how to apply an XSL transformation. You can do this in many different ways, but for now xsltproc (part of libxslt) and your browser (Firefox/Mozilla/IE6) are the most convenient ways. Usually, error reporting is somewhat better at the command-line, so we advice you to use xsltproc.

Using xsltproc

Input: hello.xml

<?xml version="1.0"?>

<hello>World</hello>

Transformation: world.xsl

<?xml version="1.0"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html" indent="yes"/>

  <xsl:template match="hello">
    <html>
      <head>
        <title>Hello <xsl:value-of select="."/></title>
      </head>
      <body>
   <h1>Hello <xsl:value-of select="."/></h1>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>

Apply xsltproc:

$ xsltproc world.xsl hello.xml

You can save the output in a file to view it in your browser:

$ xsltproc world.xsl hello.xml > hello.html

Using XSLT in a Browser

For your browser, you can add processing instruction that tells the browser to apply a stylesheet to the XML file.

Input: hello-browser.xml

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="world.xsl"?>

<hello>World</hello>

This should show a somewhat big Hello World message if you open this xml file.

A Simple XSL Transformation

In this exercise, we will style information about a Subversion repository to HTML. First of all, checkout the data of the GW wiki of last year using the command:

$ svn checkout https://svn.cs.uu.nl:12443/repos/test-wiki/

and go to the directory test-wiki. You will see all kinds of files here, which are part of the data of the wiki of last year. For example, the file WonderLand tells you a nice story about a young girl.

Now, suppose that we want know what has been going on this wiki. We can request the log to see who has committed what, when, and why.

$ svn log --verbose

This information is very useful, but hard to process for a computer program. Therefore, the Subversion developers have implemented support for getting the log in an XML format.

$ svn log --xml --verbose

Of course this is horrible to read, but for a computer program this is perfect, since there are a lot of standard languages and libraries to process XML files. We will process this XML format to a nice HTML file in the next exercise, but you will first implement a small XSLT stylesheet. You could skip to the next exercise if you already know the basics of XSLT.

First, modify one of the files. For example, give your personal touch to the Alice in Wonderland story. You've now changed one of the files in the Subversion checkout, and one of the operations a version management system has to support is to give you information about what you've been doing in a checkout. You can do this with the command:

$ svn status

You can get more information about all the files by adding the --verbose option to the command:

$ svn status --verbose.

This information is very useful, for you, as well as for computer programs. Unfortunately, the Subversion developers have not yet implemented an XML option for the svn status command.

For example, the following format could be used for that:

<?xml version="1.0"?>

<status>
  <file path="Wonderland">
    <changes>
      <modified/>
    </changes>
    <working-revision>12766</working-revision>
    <last-committed>
      <revision>12734</revision>
      <author>that's you</author>
    </last-committed>
  </file>

  <file path="trunk/WebLeftBar">
    <changes/>
    <working-revision>12766</working-revision>
    <last-committed>
      <revision>12734</revision>
      <author>mbravenboer</author>
    </last-committed>
  </file>

  <file path="trunk/WebHome">
    <changes>
      <added/>
    </changes>
    <working-revision>12766</working-revision>
    <last-committed>
      <revision>1234</revision>
      <author>visser</author>
    </last-committed>
  </file>
</status>

Now, implement an XSL Transformation that transforms this format to a simple HTML table. For example, produce the following output for the given input:

<html>
  <head>
    <title>Subversion Status</title>
  </head>
  <body>
    <table cellspacing="10">
      <tr>
        <th>Path</th>
        <th>Changes</th>
        <th>Working Revision</th>
        <th>Last Committed Revision</th>
        <th>Last Committed Author</th>
      </tr>
      <tr>
        <td>Wonderland</td>
        <td>A</td>
        <td>12766</td>
        <td>12734</td>
        <td>that's you</td>
      </tr>
      <tr>
        <td>trunk/WebLeftBar</td>
        <td/>
        <td>12766</td>
        <td>12734</td>
        <td>mbravenboer</td>
      </tr>
      <tr>
        <td>trunk/WebHome</td>
        <td>A</td>
        <td>12766</td>
        <td>1234</td>
        <td>visser</td>
      </tr>
    </table>
  </body>
</html>

More Complete XSL Transformations

Let's now try to do something more interesting, useful, and fancy. The svn log commands gives us a lot of information. Let's try to transform that to an attractive HTML page. The goal is to produce something that looks like this:

Don't worry: we give you a CSS stylesheet and images. They are available here:

Download the tarball, and use tar zxvf svnlog.tar.gz to extract the files.

Next, dump the XML log to a file:

$ svn log --xml --verbose > svnlog.xml

To help you a bit, we give you HTML skeletons for the different parts of the Subversion log. The skeleton of the resulting HTML file should be something like:

<html>
  <head>
    <title>Subversion Log</title>
    <link rel="stylesheet" type="text/css" href="svnlog.css"/>
  </head>
  <body>
    ....
  </body>
</html>

The skeleton of a logentry:

    <div class="logentry">
      <p>
        <a name="1111"/>
        <img src="page_number_24.gif" align="middle"/>
        <a href="#1111" title="Link to this commit">1111</a>
        <img src="calendar_24.gif" align="middle" style="margin-left: 15pt"/>
        2005-01-03 15:24
        <img src="user_24.gif" align="middle" style="margin-left: 15pt"/>
        username
      </p>

      <div class="commitmsg">
        <pre width="85">
          <code>
            ...
          </code>
        </pre>
      </div>
      
      <table border="0" cellspacing="5">
        ... paths ...
      </table>
    </div>

For every path in the logentry, there should be a table row in the table of the previous skeleton. In the next skeleton for a path, path, previousrevision, and thisrevision should be replaced by their actual values.

    <tr>
      <td>
        <img src="edit_16.gif" title="Modified"/>
        or 
        <img src="plus_16.gif" title="Added"/>
        or
        <img src="delete_16.gif" title="Deleted"/>
      </td>

      <td>path</td>

      <td>
        <a href="https://svn.cs.uu.nl:12443/repos/test-wiki/path" title="Open file">
          <img border="0" src="open_16.gif"/>
        </a>
      </td>

      <td>
        <a href="https://svn.cs.uu.nl:12443/viewcvs/test-wiki/path" title="Open file in ViewCVS">
          <img border="0" src="zoom_16.gif"/>
        </a>
      </td>

      <td>
        if this path was modified:
        <a
          href="https://svn.cs.uu.nl:12443/viewcvs/test-wiki/path?r1=previousrevision&amp;r2=thisrevision&amp;p1=path&amp;p2=path"
             title="View difference to previous revision in ViewCVS">
            <img border="0" src="window_tile_vert_16.gif"/>
        </a>
      </td>
    </tr>

One of the tricky parts is the transformation of the date. The problem with the date in the XML input is that is not represented in XML and therefore it is difficult to process. We give you the XSLT code for that, but you will improve this code in the next exercise:

<xsl:value-of select="substring(date/text(), 1, 4)"/>
<xsl:text>-</xsl:text>
<xsl:value-of select="substring(date/text(), 6, 2)"/>
<xsl:text>-</xsl:text>
<xsl:value-of select="substring(date/text(), 9, 2)"/>
<xsl:text> </xsl:text>
<xsl:value-of select="substring(date/text(), 12, 2)"/>
<xsl:text>:</xsl:text>
<xsl:value-of select="substring(date/text(), 15, 2)"/>

Another tricky part is the link to the viewcvs page. You need the previous revision number for that. You can do this with the axis ancestor. Ask your neighbor, or skip this if you really cannot find out how this works.

Tip: it is good style to use recursive calls to separate templates and not explicit control-flow, using for example for-each. Try to use separate templates for the modified, added, and deleted images. For this, you have to make a template that matches these specific actions.

Using the EXSLT extensions

Of course, the code for the representation of a date is horrible. The type of this date format is one of the XML Schema data types. Fortunately, XSLT is an extensible language and the community has standardized a useful set of XSLT extensions. One of these extensions is the handling of dates and times.

To use this extension for dates and times, you have to add the following declarations to the xsl:stylesheet element:

  xmlns:date="http://exslt.org/dates-and-times"
  extension-element-prefixes="date">

You can now use the functions define in the date namespace. They are explained here:

Example:

  <xsl:value-of select="date:year(date/text())"/>

Now change your stylesheet to format the date using these functions (year, month-in-year, etc).