RE: Sorting on a variable

Subject: RE: Sorting on a variable
From: Kay Michael <Michael.Kay@xxxxxxx>
Date: Mon, 16 Oct 2000 10:39:44 +0100
This is one of those things that "can't be done" in standard XSLT.

Two suggestions:
- create an (unsorted) copy of the node-set, adding the computed sort key as
an additional attribute, then use the node-set() extension to do a second
pass.
- use the saxon:function extension, which allows you to write an extension
function in XSLT and use it in contexts such as a sort key.
- try to write your computed sort key in pure XPath. Without conditional
expressions, it's not easy, but it can be done. There's a horrible hack that
relies on strange properties of the substring function:

substring("xyz", 1 div (condition)) equals "xyz" if condition is true, and
"" if condition is false.

Mike Kay

> -----Original Message-----
> From: John E. Simpson [mailto:simpson@xxxxxxxxxxx]
> Sent: 15 October 2000 18:06
> To: xsl-list@xxxxxxxxxxxxxxxx
> Subject: Sorting on a variable
> 
> 
> I've got XML which looks like this:
> 
> <products>
>    <product prodID="A1234">
>      <name>First prod</name>
>      <price curr="USD">29.95</price>
>    </product>
>    <product prodID="A5678">
>      <name>Second prod</name>
>      <price curr="GBP">29.95</price>
>    </product>
>    <product prodID="A9012">
>      <name>Third prod</name>
>      <price curr="EU">29.95</price>
>    </product>
>    <product prodID="A9012">
>      <name>Fourth prod</name>
>      <price curr="USD">50.00</price>
>    </product>
> </products>
> 
> No problem at all displaying this as a table, sorted (or not) 
> by name or 
> price. But then I wanted to sort not by raw price, but by a 
> single "USD 
> equivalent" -- converting the price to a common denomination.
> 
> Here's a variable to do the conversion (rates as of last night :):
> 
> <xsl:variable name="usd_equiv">
>    <xsl:choose>
>      <xsl:when test="price/@curr='USD'">
>        <xsl:value-of select="price"/>
>      </xsl:when>
>      <xsl:when test="price/@curr='GBP'">
>        <xsl:value-of select="price * 1.47275"/>
>      </xsl:when>
>      <xsl:when test="price/@curr='EU'">
>        <xsl:value-of select="price * 0.864379"/>
>      </xsl:when>
>      <xsl:otherwise>Unknown Currency</xsl:otherwise>
>    </xsl:choose>
> </xsl:variable>
> 
> (I've varied the values of the xsl:when test attributes in 
> different ways; 
> this is just the most current iteration, which assumes the 
> context node to 
> be a <product> element.)
> 
> Using a variable with xsl:sort introduces a number of 
> stylesheet structural 
> problems. E.g., if you do the sort within a for-each, the 
> xsl:sort must be 
> a first child of the xsl:for-each... and of course the 
> variable goes out of 
> scope for use *by* the xsl:sort. But if you do xsl:sort as a child of 
> xsl:apply-templates, well, xsl:variable is not a legitimate child of 
> xsl:apply-templates.
> 
> So then, rethinking a bit, I came up with what I thought was a fairly 
> simple solution, a global variable:
> 
> <xsl:variable name="product_usd">
>    <xsl:for-each select="/products/product">
>      <xsl:copy-of select="."/>
>      <usd_equiv>
>        <xsl:choose>
>          <xsl:when test="price/@curr='USD'">
>            <xsl:value-of select="price"/>
>          </xsl:when>
>          <xsl:when test="price/@curr='GBP'">
>            <xsl:value-of select="price * 1.47275"/>
>          </xsl:when>
>          <xsl:when test="price/@curr='EU'">
>            <xsl:value-of select="price * 0.864379"/>
>          </xsl:when>
>          <xsl:otherwise>Unknown Currency</xsl:otherwise>
>        </xsl:choose>
>      </usd_equiv>
>    </xsl:for-each>
> </xsl:variable>
> 
> Basically, this clones the <product> elements from the source 
> tree (with 
> xsl:copy-of select=".") into a variable ($prod_usd) as an 
> RTF. And -- I 
> thought -- it added an extra child element, <usd_equiv>, as a 
> child of each 
> <product> element. Then in the xsl:sort, instead of sorting 
> the source 
> tree, I'm sorting (with the node-set() function converting 
> this RTF to a 
> true node-set) the RTF contained by this variable, with 
> <usd_equiv> as my 
> sort key.
> 
> Near as I can tell, this should be giving me *something*. The 
> problem is 
> that the <usd_equiv> element always seems to be empty.
> 
> I feel really stupid. Must be missing something obvious... 
> and at this 
> point, have been banging my head against the problem for, 
> like, 6 hours.
> 
> Any ideas?
> 
> THANKS in advance!
> ===============================================================
> John E. Simpson               | "He asked me if I knew what
> http://www.flixml.org         | time it was. I said, 'Yes, but
> XML Q&A: http://www.xml.com   | not right now.'" (Steven Wright) 
> 
> 
>  XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
> 


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread