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.

Tip: Keep context straight in XSLT

Use the current() function as an anchor for XPath expressions

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:  Developers frequently forget where context changes in XPath. XSLT provides an anchor for the initial context used for XPath expressions -- the current() function. In this tip, Uche Ogbuji warns about common bugs associated with changing context, and explains how to use current(). To follow this tip, you should be familiar with the basics of XPath and XSLT.

View more content in this series

Date:  01 Feb 2003
Level:  Intermediate

Comments:  

A very common error in XPath and XSLT is to miss where context changes take place. Listing 1 (assignments.xml) is an example of a source document that records assignments of people to various tasks, with back-ups in case a primarily assigned person becomes unavailable.


Listing 1. XML document recording task assignments (assignments.xml)
                

<?xml version="1.0" encoding="utf-8"?>
<assignments>
  <task id="t1">
    <assigned-to>
      <person primary-to="t1">Uche</person>
    </assigned-to>
    <assigned-to>
      <person>Jideobi</person>
    </assigned-to>
  </task>
  <task id="t2">
    <assigned-to>
      <person primary-to="t1">Uche</person>
    </assigned-to>
    <assigned-to>
      <person primary-to="t2">Lori</person>
    </assigned-to>
  </task>
  <task id="t3">
    <assigned-to>
      <person primary-to="t3">Osita</person>
    </assigned-to>
    <assigned-to>
      <person>Jideobi</person>
    </assigned-to>
    <assigned-to>
      <person primary-to="t2">Lori</person>
    </assigned-to>
  </task>
</assignments>

The design of this XML format is not ideal (it's repetitious, for one thing), but it does illustrate the point well enough. If I want to write some XSLT to display each task and its primarily assigned party, I might write a script like that in Listing 2 (primaries.xslt).


Listing 2. XSLT transform for displaying the primary assignments for each task (primaries.xslt)
                

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="1.0">

  <xsl:output method="text"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="task">
    <xsl:value-of select="@id"/>
    <xsl:text>: </xsl:text>
    <xsl:value-of select="assigned-to/person[@primary-to = @id]"/>
    <!-- Print new line -->
    <xsl:text>
</xsl:text>
  </xsl:template>

</xsl:stylesheet>

But this does not display the desired result at all. There are no matches from each task to its primary person. The problem lies in the XPath assigned-to/person[@primary-to = @id]. Originally, the context node was a task element, as selected by the template. This is why I could extract the current task's ID with the simple XPath @id in the earlier XPath expression. However, the first step -- assigned-to -- selects all child elements with that name and shifts the context to iterate over this list.

In the next step, person[@primary-to = @id], a list of person elements is gathered, and then the context node is shifted to each in turn as the predicate [@primary-to = @id] is evaluated. Since the context for this evaluation is a person element, the @primary-to sub expression returns an attribute, as expected, from that element. The @id sub-expression, however, is a different matter. There is no such attribute on any person element, so this always returns an empty node set. What I really want is the id attribute on the task element that is an ancestor of the context node.

One way to do this is to use specific XPath operations within the predicate, such as [@primary-to = ../../@id] or [@primary-to = ancestor::*/@id]. But though these would work in the current example, they are not very general solutions because there is not always a consistent path back to the desired node. The most general solution is to have some sort of anchor back to the original context node that was passed to the overall XPath expression. XSLT provides precisely this with the current() function. Listing 3 (primaries.xslt) is a working version of my desired transform, using the current() function.


Listing 3. XSLT transform for displaying the primary assignments for each task, using current() (primaries.xslt)
                

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="1.0">

  <xsl:output method="text"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="task">
    <xsl:value-of select="@id"/>
    <xsl:text>: </xsl:text>
    <xsl:value-of 
        select="assigned-to/person[@primary-to=current()/@id]"/>
    <!-- Print new line -->
    <xsl:text>
</xsl:text>
  </xsl:template>

</xsl:stylesheet>

The current() function returns a node set whose sole item is the original context node from XSLT at the point where XPath was evaluated -- in this case, the current task element. This provides exactly what I need to compare the person's primary assignment to the desired ID in the step person[@primary-to = current()/@id]. The result of this transform is as follows:

$ 4xslt assignments.xml primaries.xslt
t1: Uche
t2: Lori
t3: Osita

Conclusion

One technique that would work pretty much anywhere that current() works is to set a variable such as <xsl:variable name="current" select="."/> for the targeted XPath expression. The main advantage of current() over this is that it makes the expression stand alone better, making it easier to reuse the expression in other settings. Context is perhaps the most important concept in XSLT, and you should learn all the tools available for handling context, including the current() function.


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=12346
ArticleTitle=Tip: Keep context straight in XSLT
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).