xsl-list
[Top] [All Lists]

RE: Complex sorting problem (looking for an XSLT outer join ?)

2003-01-16 13:02:40
Hi Philippe,

If we assume that I want to restrict myself to XSLT 1.0, do you think it
would be possible to write something with more elegance than the following
monstrosity?

tt

<?xml version="1.0"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
version="1.0">
        
        <xsl:output method="html"/>
        
        <xsl:key name="weight" match="/root/categories/category/@weight"
use="../@id"/>

        <xsl:variable name="match2"
select="/root/items/item[key('weight',@category)=2]"/>
        <xsl:variable name="match1"
select="/root/items/item[key('weight',@category)=1]"/>
        <xsl:variable name="match0"
select="/root/items/item[key('weight',@category)=0]"/>
        <xsl:variable name="missing"
select="/root/items/item[not(key('weight',@category))]"/>
        <xsl:variable name="match1all" select="$match1|$missing"/>

        <xsl:template match="/">
                <table border="1">
                        <tr>
                                <td><b>data</b></td>
                                <td><b>weight</b></td>
                                <td><b>date</b></td>
                        </tr>
                        <xsl:for-each select="$match2[position() &lt; 5]">
                                <xsl:sort select="date/@year"
order="descending" data-type="number"/>
                                <xsl:sort select="date/@month"
order="descending" data-type="number"/>
                                <xsl:sort select="date/@day"
order="descending" data-type="number"/>
                                <xsl:call-template name="dump-item">
                                        <xsl:with-param name="item"
select="."/>
                                </xsl:call-template>
                        </xsl:for-each>
                        <xsl:for-each select="$match1all[position() &lt;
(5-count($match2))]">
                                <xsl:sort select="date/@year"
order="descending" data-type="number"/>
                                <xsl:sort select="date/@month"
order="descending" data-type="number"/>
                                <xsl:sort select="date/@day"
order="descending" data-type="number"/>
                                <xsl:call-template name="dump-item">
                                        <xsl:with-param name="item"
select="."/>
                                </xsl:call-template>
                        </xsl:for-each>
                        <xsl:for-each select="$match0[position() &lt;
(5-count($match2)-count(match1all))]">
                                <xsl:sort select="date/@year"
order="descending" data-type="number"/>
                                <xsl:sort select="date/@month"
order="descending" data-type="number"/>
                                <xsl:sort select="date/@day"
order="descending" data-type="number"/>
                                <xsl:call-template name="dump-item">
                                        <xsl:with-param name="item"
select="."/>
                                </xsl:call-template>
                        </xsl:for-each>
                </table>
                
        </xsl:template>
        
        <xsl:template name="dump-item">
                <xsl:param name="item"/>
                <tr>
                        <td>
                                <xsl:value-of select="$item/@data"/>
                        </td>
                        <td>
                                <xsl:value-of
select="key('weight',$item/@category)"/>
                        </td>           
                        <td>
                                <xsl:value-of select="date/@year"/>
                                <xsl:text>/</xsl:text>
                                <xsl:value-of select="date/@month"/>
                                <xsl:text>/</xsl:text>
                                <xsl:value-of select="date/@day"/>
                        </td>
                </tr>   
        </xsl:template>

</xsl:stylesheet>

:-)

-----Original Message-----
From: Philippe Drix [mailto:pdrix(_at_)objectiva(_dot_)fr]
Sent: Thursday, January 16, 2003 7:13 PM
To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
Subject: Re: [xsl] Complex sorting problem (looking for an XSLT outer
join?)


At 18:43 16/01/2003 +0100, you wrote:
Hi,

My source xml has the following format:

<root>
    <items>
        <item category="1" data="ggg">
            <date year="1995" month="4" day="13"/>
        </item>
        <item category="2" data="hhh">
            <date year="1984" month="7" day="22"/>
        </item>
        <item category="3" data="www">
            <date year="1991" month="3" day="12"/>
        </item>
        <item category="3" data="rrr">
            <date year="1999" month="6" day="19"/>
        </item>
        <item category="4" data="xxx">
            <date year="1982" month="2" day="17"/>
        </item>
        <item category="5" data="kkk">
            <date year="2000" month="12" day="11"/>
        </item>
    </items>

    <categories>
        <category id="1" weight="0">
        <category id="3" weight="2">
        <category id="4" weight="1">
    </categories>
</root>

1) The source xml contains a list of items.
   Each item carries a 'data' attribute, which is the 
actual content of the
item.
   Apart from that, each item contains:
   a) a 'catagory' attribute, identifying the catagory that 
the item belogs
to.
   b) a 'date' child element, representing the date of the item
   Each item has an implied weight, implied by the category that it
references. (but see [2] and [3])

2) The source xml also contains a list of categories.
   Each category contains a 'weight' attribute, which carries the
'importance' of the category.
   Weight is from 0 (least important) to 2 (most 
important), in other words
[0,2].

3) Some of the categories referred to by the item elements 
are not present
in the source xml.
   A default weight of 1 should be assumed in that case.
   In the example xml, the categories (2,5) are absent.

I would like to sort the item elements using the following criteria:
   1) first, by (implied) weight
   2) second, by date

It seems to me that the problem would be easy if all 
referenced categories
were present in the source xml.
In that case, I could use xsl:key to retreive the matching 
weight for each
item.

However, that is not the case. It seems that what I want is to grab a
default weight of 1 wherever the references category is not 
present in the
source xml.
Using SQL, for instance, I could use an outer join, 
specifying a default
value.

Is there any solution for this problem in XSLT?

Thanks in advance for any feedback,

tt







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


You can copy your XML into a variable, but with a copy that will not be a 
true copy, because you will have to instanciate attribute "weight", 
defaulted to value 1 if absent.
Then you put the current node on the root of this variable (use Saxon with 
version="1.1", or use a function like node-set() to convert RTF to 
nodes-set ):
<xsl:for-each select="$myNewXMLtreeWithAttributeWeightAlwaysPresent">
         <xsl:for-each select="what you want">
                 <xsl:sort what you want>
         </xsl:for-each>
</xsl:for-each>
Regards -- Ph D

==
Philippe Drix
      ___________
__| OBJECTIVA |___________________
http://www.objectiva.fr
21-23, rue Aristide Briand - 92170 Vanves
tel : +33 1 47 36 60 30
fax : +33 1 47 36 61 93



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

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



<Prev in Thread] Current Thread [Next in Thread>
  • RE: Complex sorting problem (looking for an XSLT outer join ?), Taras Tielkes <=