Click to See Complete Forum and Search --> : A sorted XPATH location


websmith99
January 3rd, 2003, 03:41 PM
I was wondering if it's possible to sort an XPATH location. Here
is basically what I'm trying to solve:

The XML document is of the following format:

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="export-common.xsl"?>
<items>
<item>
<first>foo</first>
<second>bar</second>
</item>
<item>
<first>web</first>
<second>smith</second>
</item>
<item>
<first>Reykjavik</first>
<second>Iceland</second>
</item>
</items>

I have an XSL stylesheet that displays the <first> and <second>
elements in an HTML table, sorted in ascending order on the
<first> element:

<xsl:sort select="first" data-type="text" order="ascending" />

Now I would like to compare the 1st letter of each <first> element
with the previous entry, to display a header if the letter is
different, like a glossary:

A
acrobat a circus performer; software by adobe
anteater an animal that eats ants

B
border to delineate the transition from one zone to another

C
caravan etc...

So here is the XPATH expression:

<xsl:value-of select="substring(current()/preceding-sibling::item[position()=1]/first, 1, 1)" />

The problem is that the XPATH expression will reference the first letter of the previous <first> entry in the XML document, not the
sorted display.

How can the XPATH location be changed to reference the sorted
output?

websmith99
January 10th, 2003, 05:18 PM
I was able to resolve this. It requires an XSLT extension that is not part of the W3C standard and will not work on all parsers, but it works for the parser that I use - Xalan.

In the XSL file, you must define the namespace for this extension:

<xsl:stylesheet version="1.0"
xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
xmlns:exslt="http://exslt.org/common">


I then defined a variable to hold the sorted node set:

<xsl:variable name="sorteditems">

<xsl:for-each select="$root/item">
<xsl:sort select="first" data-type="text" order="ascending"/>
<xsl:copy-of select="current()" />
</xsl:for-each>

</xsl:variable>

Now here's where the extension comes in. I pass the sorted node set as a parameter to my template that uses the XPATH location:

<xsl:call-template name="my-template">
<xsl:with-param name="sorted_items" select="exslt:node-set($sorteditems)/item" />
</xsl:call-template>

Now within the template, I can continue to use the same XPATH location:

<xsl:value-of select="substring(current()/preceding-sibling::item[position()=1]/first, 1, 1)" />