Skip to main content

If you don't have an IBM ID and password, register here.

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. This profile includes the first name, last name, and display name you identified when you registered with developerWorks. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

EXSLT by example

How to put the community standard XSLT extensions to work

Uche Ogbuji (uche@ogbuji.net), Principal Consultant, Fourthought, Inc.
Photo of Uche Ogbuji
Uche Ogbuji is a consultant and co-founder of Fourthought Inc., a software vendor and consultancy specializing in XML solutions for enterprise knowledge management. Fourthought develops 4Suite, an open source platform for XML, RDF, and knowledge-management applications. Mr. Ogbuji is a computer engineer and writer born in Nigeria, living and working in Boulder, Colorado, USA. You can contact Mr. Ogbuji at uche@ogbuji.net.

Summary:  Community standards have had a very important role in XML technology, from SAX to RDDL. The most important community standard for XSLT is the EXSLT initiative for standard extension functions and elements. In this article, Uche Ogbuji uses practical examples to introduce and demonstrate some useful EXSLT functions.

Date:  01 Feb 2003
Level:  Intermediate

Comments:  

In a recent developerWorks column, "Extend XSLT's functionality with EXSLT," Kevin Williams wrote a high-level introduction to the community standard of extensions to XSLT. As he pointed out, the EXSLT extensions make XSLT far more useful in general-purpose data-manipulation tasks. Just to select a few random examples:

  • The EXSLT Math module contains trigonometric mathematical functions, which makes it feasible to generate pie charts in SVG.
  • The EXSLT Regular Expressions module makes it easier to parse and process user input and other variable data sources.
  • The EXSLT Dates and Times module makes it easier to render Web pages with date-sensitive content, or to process data containing date fields.

In these and many other real-life tasks, EXSLT makes using XSLT feasible in a way that is portable across the many processors that support the standard. In prior articles, I have already shown how EXSLT functions such as exsl:node-set and exsl:object-type are useful for even the most basic processing tasks. In this article I try to cover a cross-section of EXSLT's capabilities by solving a couple of simple and practical problems using EXSLT. I also try to avoid ground I've already covered to introduce the many useful EXSLT facilities that have not received the attention they deserve.

If you are completely unfamiliar with EXSLT, please read the Kevin Williams article first. The resources in that article include pointers to XSLT processors that support EXSLT, which you should install so you can play with the examples and use EXSLT yourself. Some EXSLT extensions can be used with arbitrary processors, using XSLT scripts you can download from the EXSLT site. But not all EXSLT modules are supported in this way, and this approach typically loses you a lot of performance. You may also want to read my other discussions of EXSLT on IBM developerWorks. You'll find pointers to such material in Resources.

Reach for your calendar

Problem: You generate a Web site upon user request on the server using XSLT. On that Web site you would like to display the current date and time, along with a countdown in days before a certain event.

The EXSLT Dates and Times module provides many functions for manipulating dates, including one for getting the current date, some for performing calculations between dates, and others for formatting, displaying, and interpreting dates. It also provides a <date:date-format/> extension element for customized date parsing and formatting.

Listing 1 demonstrates these facilities by displaying the current date and time, and the number of days until the start of the next month.


Listing 1. Sample code for computing date-specific details (listing1.xslt)
<?xml version="1.0" encoding="utf-8"?>
<!-- A -->
<xsl:transform
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:date="http://exslt.org/dates-and-times"
    version="1.0"
>
<xsl:output method="html"/>

<!-- B -->
<xsl:variable name="now" select="date:date-time()"/>

<xsl:template match="/">
  <!-- The rest of the Web site HTML material would go here -->
  <xsl:call-template name="date-section"/>
</xsl:template>

<xsl:template name="date-section">
  <p>This page was loaded at <xsl:text/>
    <!-- C -->
    <xsl:value-of select="concat(date:hour-in-day($now), ':',
                                 date:minute-in-hour($now), ':',
                                 date:second-in-minute($now))"/>
    <xsl:text> on </xsl:text>
    <xsl:value-of select="concat(date:day-in-month($now), ' ',
                                 date:month-name($now), ' ',
                                 date:year($now))"/>
  </p>
  <p>
    <!-- D -->
    <xsl:variable name="days-elapsed"
                  select="concat('-P',date:day-in-month($now),'D')"/>
    <xsl:variable name="one-month-hence"
                  select="date:add($now, 'P1M')"/>
    <xsl:variable name="next-month-start"
                  select="date:add($one-month-hence, $days-elapsed)"/>
    <xsl:variable name="seconds"
                  select="date:seconds(
                            date:difference($now, $next-month-start)
                         )"/>
    <xsl:text>The next month starts in </xsl:text>
    <xsl:value-of select="$seconds div (3600*24)"/>
    <xsl:text> days</xsl:text>
  </p>

</xsl:template>

</xsl:transform>

I shall discuss each of the lettered sections of the listing in turn.

A: First I declare the namespace for the EXSLT dates/times module: http://exslt.org/dates-and-times. Be careful to get this right. I've seen a few people make the mistake of using the specification page of the module, http://www.exslt.org/date/index.html, rather than the proper namespace, which results in errors.

B: The function date:date-time returns the current date and time as a string in ISO-8601 format, for example 2003-01-20T03:16:36Z.

C: Here I construct a readable representation of the date and time, using EXSLT functions that allow me to extract the various components from the date/time string. I could have done this several ways, including the date:date-format element, with which you use a format string to specify the look of the rendered date.

D: Here I use a few computing gymnastics to determine the number of days until the start of next month. I could have performed this calculation in numerous ways, some of them simpler, but I picked a sequence that shows off a good selection of EXSLT functions. First I compute the number of days elapsed in the current month as an EXSLT duration string. An EXSLT duration represents a duration of time rather than a period of time. For example, -P19D which means "a negative period of 19 days". Durations have signs for arithmetic purposes. For example, if you add the period P1D12H to a date/time representing midnight January 15, 2003, you get noon, January 15. If you add the period -P1D12H, you get noon, January 14 instead. Such calculation can be performed using the date:add function, which takes a date/time point and a duration.

Next in the listing I compute the date/time point one month from the present using date:add. In the case where $now is 2003-01-20T03:16:36Z, the result is 2003-02-20T03:16:36Z. Then I count back from that date the number of days that have elapsed, which gives me the first date of the next month -- for example, 2003-02-01T03:16:36Z. The function date:difference takes two date/time points and returns the duration between them. I use this to compute the duration until the next month and then the number of seconds in that duration -- for example, 1036800. Finally, I use integer division by (3600*24), to determine the number of days until the next month.

The output of this script is as follows:

<p xmlns:date="http://exslt.org/dates-and-times">This page was loaded 
at 21:16:36 on 19 January 2003</p>
<p xmlns:date="http://exslt.org/dates-and-times">The next month starts 
in 12 days</p>

Note that the above output appears on a single line but has been split to multiple lines for display purposes.


Quick and dirty database operations

Problem: You have a bunch of records that you manage in an XML file, and you would like people to be able to use general queries to retrieve particular portions of this data. In other words, you want to be able to access the XML as a quick and dirty database while processing other XML data.

Take the data file in Listing 2, which represents the departments and employees in an organization.


Listing 2. A data file of employees (employees.xml)
<?xml version="1.0" encoding="utf-8"?>
<employees>
  <department title="Research">
    <employee title="Coordinator">
      <name>
        <given>Rene</given>
        <family>Descartes</family>
      </name>
    </employee>
    <employee title="Project Manager">
      <name>
        <given>Abu</given>
        <family>Al Kwarizmi</family>
      </name>
    </employee>
  </department>
  <department title="Executive">
    <employee title="Chief Executive Officer">
      <name>
        <given>Genghis</given>
        <family>Khan</family>
      </name>
    </employee>
  </department>
  <department title="Wellness">
    <employee title="Manager of Transcendence">
      <name>
        <given>Shakyamuni</given>
        <family>Buddha</family>
      </name>
    </employee>
  </department>
</employees>

Now let's say that we want people to be able to compose memos addressed to people according to queries on this data file. Listing 3 is an example of such a memo.


Listing 3. Memo addressed according to an employee data file query (memo.xml)
<?xml version='1.0' encoding='utf-8'?>
<memo>
<title>With Usura Hath no Man a House of Good Stone</title>
<date>2003-01-14</date>
<to>
  <employee-query
    query="/employees/department[@title='Executive']/employee"/>
</to>
<body>
It appears the art world requires a reminder of the fact that the best 
art is created for the enjoyment of the first buyer, and not as as a 
mere investment.  As I've said before, none of the work of Duccio, Piero 
Della Francesca, Pietro Lombardo, Fra Angelico, Zuan Bellini or such 
others would have been of any value if guided by usurious motives.

--EP
</body>
</memo>

The to element contains an employee-query element, which should be replaced by the result of the query it specifies on the employee data file. Listing 4 is a small XSLT file that demonstrates how this process would work by displaying the actual names of the recipients of the memo.


Listing 4. XSLT file that displays memo recipients (listing4.xslt)
<?xml version="1.0" encoding="utf-8"?>
<!-- A -->
<xsl:transform
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:dyn="http://exslt.org/dynamic"
    version="1.0"
>

<xsl:output method="text"/>

<xsl:template match="/">
  <!-- Jump right to the to element -->
  <xsl:apply-templates select="/memo/to"/>
</xsl:template>

<xsl:template match="to">
  <xsl:apply-templates/>
</xsl:template>

<!-- B -->
<xsl:template match="employee-query">
  <xsl:variable name="db" select="document('employees.xml')"/>
  <xsl:variable name="query" select="@query"/>
  <xsl:for-each select="$db">
    <xsl:variable name="recipients" select="dyn:evaluate($query)"/>
    <xsl:apply-templates select="$recipients"/>
  </xsl:for-each>
</xsl:template>

<xsl:template match="employee">
  <xsl:value-of select="name/given"/>
  <xsl:text> </xsl:text>
  <xsl:value-of select="name/family"/>
  <xsl:if test="not(position()=last())">
    <xsl:text>, </xsl:text>
  </xsl:if>
</xsl:template>

</xsl:transform>

A: Notice the different namespace that I use to set up the EXSLT module: http://exslt.org/dynamic. This module contains several functions that process strings as XPaths in real-time, and in some cases perform aggregate calculations based on such strings.

B: This template is where the real action takes place. First I read in the data file as secondary input. Then I store the query string in a variable. I have to do this because soon I'll have to shift the context so that the attribute in which this string appears is no longer readily available. The xsl:for-each element actually makes the context shift to the data file. Then dyn:evaluate function dynamically evaluates the query string against this context. The resulting node set is returned as if from a regular XPath expression evaluation. XSLT 1.0 has no way to evaluate a string dynamically as an XPath expression, but by using EXSLT I gain this capability. In the rest of the listing, conventional XSLT operations are used to print the names that come from the elements in the query result.


Summary

EXSLT includes tools for making things easier and others for making things possible in the first place. For example, the date:date-time function is impossible to replace in XSLT but dyn:evaluate() can usually be replaced by a system, whereas you use XSLT to generate another XSLT script which is what you actually run to get the desired result. EXSLT includes much more than I can hope to cover in future articles, but one nice thing about EXSLT is that it is very well documented. You'll find a world of riches to improve your XSLT development by checking out the Web site and taking advantage of this community standard.


Resources

About the author

Photo of Uche Ogbuji

Uche Ogbuji is a consultant and co-founder of Fourthought Inc., a software vendor and consultancy specializing in XML solutions for enterprise knowledge management. Fourthought develops 4Suite, an open source platform for XML, RDF, and knowledge-management applications. Mr. Ogbuji is a computer engineer and writer born in Nigeria, living and working in Boulder, Colorado, USA. You can contact Mr. Ogbuji at uche@ogbuji.net.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in

If you don't have an IBM ID and password, register here.


Forgot your IBM ID?


Forgot your password?
Change your password


By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. This profile includes the first name, last name, and display name you identified when you registered with developerWorks. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)


By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML
ArticleID=12213
ArticleTitle=EXSLT by example
publish-date=02012003
author1-email=uche@ogbuji.net
author1-email-cc=

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).