XSLT group-by

While doing some reading (or catching up) on new features in XSLT 2.0, I came upon a very useful addition. It is possible to implement this in XSLT 1.0, though rather painfully, but it’s a lot more intuitive in 2.0. Let’s say we have the following XML data with employee bonus amounts:

<company>

<employee name=”Matt” quarter=”q1″ amount=”700″/>

<employee name=”Matt” quarter=”q2″ amount=”200″/>

<employee name=”Matt” quarter=”q1″ amount=”300″/>

<employee name=”SamosaMan” quarter=”q1″ amount=”400″/>

<employee name=”SamosaMan” quarter=”q2″ amount=”60″/>

</company>

I would like to display an HTML page to summarize each employee’s bonus amounts grouped by quarters (q1, q2, etc).

  1. First we use the tag xsl:for-each-group and select the initial list of employees with select clause as ‘company/employee’.
  2. We also tell the transformer engine to group the resulting sequence of nodes using group-by=’@name’.
  3. With this we now have a sequence of employee nodes grouped by the employee name.
  4. Now we can print the name of each employee. But we need to go one level deeper and summarize their bonus amounts by quarter. As you can see these employees are lucky in that they get multiple bonuses in the same quarter.
  5. Now for the current employee lets do another group-by against the quarter attribute with
  6. Point to note is the use of select=’current-group()’ which gives us a way to reference the current employee being processed. The rest should be obvious.

The display (once you fill in the blanks around the XSLT) is:

The java code to transform and print the HTML to the console:

Last but not the least you will need a XSLT parser that supports XSLT 2.0 and XPATH 2.0. Neither of the specs are final releases yet. But Saxon has an implementation of the pre-release version out for use.

Before I stop I do want to make sure that the reader is ‘aware’ of how the java runtime ‘knows’ which XSLT engine to use. Remember JAXP. Well it was created to insulate the developers from the gory implementation details of different vendor implementations. So in our case we may want to use Apache Xalan as our XSLT processor or like in my case I used Saxon’s implementation. I used Saxon cause their current release supports XSLT 2.0 on which this blog is based on.

Ok so how do we tell Java to use our choice of XSLT processor? One of three ways in order:

  1. You can pass the system property -Djavax.xml.transform.TransformerFactory=net.sf.saxon.TransformerFactoryImpl
  2. If the system property could not be located..next the JRE lib/jaxp.properties is checked for the same name value pair mentioned above.
  3. If 1 and 2 fails then the service provider mechanism is used to locate the implementation. This is what my example used. How do I know that? Check the file META-INF/services/javax.xml.transform.TransformerFactory in saxon8.jar. It contains ‘net.sf.saxon.TransformerFactoryImpl’.
  4. Finally if all fails then the default implementation will be used as shipped with the JDK.