correctly sorting and pagination XSL

Hi,

I've created an XSL that reads in XML data and transforms it successfully. I have introduced sorting which is working perfectly, then I added pagination which works but when they are both used together the results aren't exactly what I want.

Say I have 12 records that match the criteria of the xsl, If I limit the page size to 5 records and sort by price descending then it sorts the first page of results but doesn't necessarily put the most expensive of the 12 at the top, just the most expensive on that page of results. On the other 2 pages there could be more expensive ones.

How do I make this so that if I sort by price descending it sorts the records then paginates. so that the order is correct, and then the order is maintained as they scroll through the pages.

I can add my XSL if you would like to see what I am doing currently.

Thanks
help-is-neededAsked:
Who is Participating?
 
Geert BormansInformation ArchitectCommented:
OK, we have been to this point before :-)

The issue is in the use of position().
That works on the entire set

     <xsl:for-each select="Product[position() >= $first and position() &lt; $first + $size and (translate(normalize-space(Story/Desc_Destinations), 'AZERTYUIOPQSDFGHJKLMWXCVBN', 'azertyuiopqsdfghjklmwxcvbn') = translate(normalize-space($DestToSelect), 'AZERTYUIOPQSDFGHJKLMWXCVBN', 'azertyuiopqsdfghjklmwxcvbn'))]">
        <xsl:sort data-type="number" order="ascending" select="Story/Price"/>
        <xsl:call-template name="hotel-teaser" />
      </xsl:for-each>

I think it would work if you did do this like this

     <xsl:for-each select="Product[(translate(normalize-space(Story/Desc_Destinations), 'AZERTYUIOPQSDFGHJKLMWXCVBN', 'azertyuiopqsdfghjklmwxcvbn') = translate(normalize-space($DestToSelect), 'AZERTYUIOPQSDFGHJKLMWXCVBN', 'azertyuiopqsdfghjklmwxcvbn'))]">
        <xsl:sort data-type="number" order="ascending" select="Story/Price"/>
<xsl:if test="position() >= $first and position() &lt; $first + $size">
        <xsl:call-template name="hotel-teaser" />
</xsl:if>

If you would be able to use a nodeset, it would be easier
(but then you need to tell me which XSLT processor you are using)
      </xsl:for-each>

0
 
Geert BormansInformation ArchitectCommented:
That is likely because you are doing the paging first and after that order the page
(which is not an uncommon problem)

Note that if you would be using the preceding-sibling axis or following-sibling axis,
those operate on the elements in document order, not in sorted order

I suggested in this project that you would do the filtering and sorting in a first XSLT
and you would deal with the paging after that.
This suggestion had a reason... exactly this problem
Doing so would dramatically take down the amount of code you would need and would lessen the risk for errors

Are you still doing this in two steps? or did you abandon that approach.
I recommend still to make it two steps
0
 
help-is-neededAuthor Commented:
Hi Gertone,

Unfortunately due to the set up of the server and the content management system that is is due to run on it needs to be contained within the one XSLT. So I've had to abandon that.

Here is my code.. the transformation is done using some script on the server that feeds the variables and parameters in from the querystring.

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

  <xsl:variable name="lowercase" select="'abcdefghijklmnopqrstuvwxyz'" />
  <xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
  <xsl:variable name="sf_price">Price</xsl:variable>
	<xsl:variable name="sf_rating">Rating</xsl:variable>
  <xsl:variable name="sf_resort_name">Resort</xsl:variable>
  <xsl:variable name="uparrow">up-arrow.jpg</xsl:variable>
  <xsl:variable name="downarrow">down-arrow.jpg</xsl:variable>
  <xsl:variable name="pound">£</xsl:variable>
  <xsl:variable name="uparrow-on">up-arrow-on.gif</xsl:variable>
  <xsl:variable name="downarrow-on">down-arrow-on.gif</xsl:variable>

  <xsl:variable name="DestToSelect">Byron Bay</xsl:variable>
  <xsl:variable name="sort">Price</xsl:variable>
  <xsl:variable name="sort_order">ascending</xsl:variable>
  <xsl:variable name="data_type">
    <xsl:choose>
      <xsl:when test="$sort='Price'">number</xsl:when>
      <xsl:when test="$sort='Product_Rating'">number</xsl:when>
      <xsl:otherwise>text</xsl:otherwise>
    </xsl:choose>
  </xsl:variable>
  <xsl:param name="first">1</xsl:param>
  <xsl:param name="size">5</xsl:param>
  
<xsl:template match="Root">
  <div>
    <xsl:call-template name="navigation"/>
  </div>
	<table style="background-color: #364750; color:#ffffff; width:960px; margin-top:5px" >
		<tr>
      <td width="600px"></td>
			<td width="40px"><xsl:value-of select="$sf_price"/></td>
			<td width="80px">
			  <xsl:choose>  
				<xsl:when test="$sort_order='ascending' and $sort='Price'">
				  <img alt="Sort ascending selected" src="{$downarrow-on}"/>
				  <a href="?sort=Price&amp;sort_order=descending">
					<img alt="Sort descending" src="{$uparrow}"/>
				  </a>
				</xsl:when>
				<xsl:when test="$sort_order='descending' and $sort='Price'">
				  <a href="?sort=Price&amp;sort_order=ascending">
					<img alt="Sort ascending" src="{$downarrow}"/>
				  </a>
				  <img alt="Sort descending selected" src="{$uparrow-on}"/>
				</xsl:when>
				<xsl:otherwise>
				  <a href="?sort=Price&amp;sort_order=ascending">
					<img alt="Sort ascending" src="{$uparrow}"/>
				  </a>
				  <a href="?sort=Price&amp;sort_order=descending">
					<img alt="Sort descending" src="{$downarrow}"/>
				  </a>
				</xsl:otherwise> 
			  </xsl:choose>
			</td>
			<td width="40px">
				<xsl:value-of select="$sf_rating"/>
			</td>
			<td>
				<xsl:choose>
					<xsl:when test="$sort_order='ascending' and $sort='Product_Rating'">
						<img alt="Sort ascending selected" src="{$downarrow-on}"/>
						<a href="?sort=Product_Rating&amp;sort_order=descending">
							<img alt="Sort descending" src="{$uparrow}"/>
						</a>
					</xsl:when>
					<xsl:when test="$sort_order='descending' and $sort='Product_Rating'">
						<a href="?sort=Product_Rating&amp;sort_order=ascending">
							<img alt="Sort ascending" src="{$downarrow}"/>
						</a>
						<img alt="Sort descending selected" src="{$uparrow-on}"/>
					</xsl:when>
					<xsl:otherwise>
						<a href="?sort=Product_Rating&amp;sort_order=ascending">
							<img alt="Sort ascending" src="{$downarrow}"/>
						</a>
						<a href="?sort=Product_Rating&amp;sort_order=descending">
							<img alt="Sort descending" src="{$uparrow}"/>
						</a>
					</xsl:otherwise>
				</xsl:choose>
			</td>
      <td width="40px">
        <xsl:value-of select="$sf_resort_name"/>
      </td>
      <td>
        <xsl:choose>
          <xsl:when test="$sort_order='ascending' and $sort='ServiceName'">
            <img alt="Sort ascending selected" src="{$downarrow-on}"/>
            <a href="?sort=ServiceName&amp;sort_order=descending">
              <img alt="Sort descending" src="{$uparrow}"/>
            </a>
          </xsl:when>
          <xsl:when test="$sort_order='descending' and $sort='ServiceName'">
            <a href="?sort=ServiceName&amp;sort_order=ascending">
              <img alt="Sort ascending" src="{$downarrow}"/>
            </a>
            <img alt="Sort descending selected" src="{$uparrow-on}"/>
          </xsl:when>
          <xsl:otherwise>
            <a href="?sort=ServiceName&amp;sort_order=ascending">
              <img alt="Sort ascending" src="{$downarrow}"/>
            </a>
            <a href="?sort=ServiceName&amp;sort_order=descending">
              <img alt="Sort descending" src="{$uparrow}"/>
            </a>
          </xsl:otherwise>
        </xsl:choose>
      </td>
		</tr>
	</table>

  <xsl:choose>
    <xsl:when test="$sort_order='ascending' and $sort='Price'">
      <xsl:for-each select="Product[position() >= $first and position() &lt; $first + $size and (translate(normalize-space(Story/Desc_Destinations), 'AZERTYUIOPQSDFGHJKLMWXCVBN', 'azertyuiopqsdfghjklmwxcvbn') = translate(normalize-space($DestToSelect), 'AZERTYUIOPQSDFGHJKLMWXCVBN', 'azertyuiopqsdfghjklmwxcvbn'))]">
        <xsl:sort data-type="number" order="ascending" select="Story/Price"/>
        <xsl:call-template name="hotel-teaser" />
      </xsl:for-each>
    </xsl:when>
    <xsl:when test="$sort_order='descending' and $sort='Price'">
      <xsl:for-each select="Product[position() >= $first and position() &lt; $first + $size and (translate(normalize-space(Story/Desc_Destinations), 'AZERTYUIOPQSDFGHJKLMWXCVBN', 'azertyuiopqsdfghjklmwxcvbn') = translate(normalize-space($DestToSelect), 'AZERTYUIOPQSDFGHJKLMWXCVBN', 'azertyuiopqsdfghjklmwxcvbn'))]">
        <xsl:sort data-type="number" order="descending" select="Story/Price"/>
        <xsl:call-template name="hotel-teaser" />
      </xsl:for-each>
    </xsl:when>
    <xsl:when test="$sort_order='ascending' and $sort='Product_Rating'">
      <xsl:for-each select="Product[position() >= $first and position() &lt; $first + $size and (translate(normalize-space(Story/Desc_Destinations), 'AZERTYUIOPQSDFGHJKLMWXCVBN', 'azertyuiopqsdfghjklmwxcvbn') = translate(normalize-space($DestToSelect), 'AZERTYUIOPQSDFGHJKLMWXCVBN', 'azertyuiopqsdfghjklmwxcvbn'))]">
        <xsl:sort data-type="number" order="ascending" select="Story/Product_Rating"/>
        <xsl:call-template name="hotel-teaser" />
      </xsl:for-each>
    </xsl:when>
    <xsl:when test="$sort_order='descending' and $sort='Product_Rating'">
      <xsl:for-each select="Product[position() >= $first and position() &lt; $first + $size and (translate(normalize-space(Story/Desc_Destinations), 'AZERTYUIOPQSDFGHJKLMWXCVBN', 'azertyuiopqsdfghjklmwxcvbn') = translate(normalize-space($DestToSelect), 'AZERTYUIOPQSDFGHJKLMWXCVBN', 'azertyuiopqsdfghjklmwxcvbn'))]">
        <xsl:sort data-type="number" order="descending" select="Story/Product_Rating"/>
        <xsl:call-template name="hotel-teaser" />
      </xsl:for-each>
    </xsl:when>
    <xsl:when test="$sort_order='ascending' and $sort='ServiceName'">
      <xsl:for-each select="Product[position() >= $first and position() &lt; $first + $size and (translate(normalize-space(Story/Desc_Destinations), 'AZERTYUIOPQSDFGHJKLMWXCVBN', 'azertyuiopqsdfghjklmwxcvbn') = translate(normalize-space($DestToSelect), 'AZERTYUIOPQSDFGHJKLMWXCVBN', 'azertyuiopqsdfghjklmwxcvbn'))]">
        <xsl:sort data-type="text" order="ascending" select="Story/ServiceName"/>
        <xsl:call-template name="hotel-teaser" />
      </xsl:for-each>
    </xsl:when>
    <xsl:when test="$sort_order='descending' and $sort='ServiceName'">
      <xsl:for-each select="Product[position() >= $first and position() &lt; $first + $size and (translate(normalize-space(Story/Desc_Destinations), 'AZERTYUIOPQSDFGHJKLMWXCVBN', 'azertyuiopqsdfghjklmwxcvbn') = translate(normalize-space($DestToSelect), 'AZERTYUIOPQSDFGHJKLMWXCVBN', 'azertyuiopqsdfghjklmwxcvbn'))]">
        <xsl:sort data-type="text" order="descending" select="Story/ServiceName"/>
        <xsl:call-template name="hotel-teaser" />
      </xsl:for-each>
    </xsl:when>
  </xsl:choose>
  
</xsl:template>

  <xsl:template name="hotel-teaser">
    <div id="TeaserBase" style="background-color: #364750; color:#ffffff; width:960px; margin-top:10px">
      <table id="teaser_content" style="padding:10px">
        <tr>
          <td>
            <div id="teaser_image" style="padding:10px 5px 10px 10px; width:430px">
              <xsl:element name="img">
                <xsl:attribute name="border">0</xsl:attribute>
                <xsl:attribute name="src">
                  <xsl:value-of select="Image_1/@href"/>
                </xsl:attribute>
                <xsl:attribute name="width">430</xsl:attribute>
                <xsl:attribute name="height">325</xsl:attribute>
                <xsl:attribute name="alt">
                  <xsl:value-of select="Story/ServiceName"/>
                </xsl:attribute>
                <xsl:attribute name="title">
                  <xsl:value-of select="Story/ServiceName"/>
                </xsl:attribute>
              </xsl:element>
            </div>
          </td>
          <td>
            <div id="teaser_right" style="padding:5px 5px 0 10px">
              <table>
                <tr>
                  <td colspan="2">
                    <div style="font-size:18px; font-weight:bold; max-width:480px">
                      <xsl:value-of select="translate(Story/ServiceName, $lowercase, $uppercase)"/>
                    </div>
                    <div>
                      <xsl:choose>
                        <xsl:when test="Story/Product_Rating = 1">
                          <img src="Star.png" alt="1" title="1" ></img>
                        </xsl:when>
                        <xsl:when test="Story/Product_Rating = 1.5">
                          <img src="Star1-5.png" alt="1.5" title="1.5" ></img>
                        </xsl:when>
                        <xsl:when test="Story/Product_Rating = 2">
                          <img src="Star2.png" alt="2" title="2" ></img>
                        </xsl:when>
                        <xsl:when test="Story/Product_Rating = 2.5">
                          <img src="Star2-5.png" alt="2.5" title="2.5" ></img>
                        </xsl:when>
                        <xsl:when test="Story/Product_Rating = 3">
                          <img src="Star3.png" alt="3" title="3" ></img>
                        </xsl:when>
                        <xsl:when test="Story/Product_Rating = 3.5">
                          <img src="Star3-5.png" alt="3.5" title="3.5" ></img>
                        </xsl:when>
                        <xsl:when test="Story/Product_Rating = 4">
                          <img src="Star4.png" alt="4" title="4" ></img>
                        </xsl:when>
                        <xsl:when test="Story/Product_Rating = 4.5">
                          <img src="Star4-5.png" alt="4.5" title="4.5" ></img>
                        </xsl:when>
                        <xsl:when test="Story/Product_Rating = 5">
                          <img src="Star5.png" alt="5" title="5" ></img>
                        </xsl:when>
                      </xsl:choose>
                      <xsl:text> </xsl:text>
                      <span style="font-size:15px; font-weight:bold">
                        <xsl:value-of select="translate(Story/Desc_Destinations, $lowercase, $uppercase)"></xsl:value-of>
                      </span>
                    </div>
                  </td>
                </tr>
                <tr>
                  <td>
                    <div id="teaser_text" style="width:290px; max-height:290px; height:290px">
                      <div style="width:280px; height:280px;">
                        <span style="font-size:12px;">
                          <xsl:value-of select="Story/Desc_Snapshot"/>
                        </span>
                      </div>
                    </div>
                  </td>
                  <td>
                    <table style="width:180px; height:290px">
                      <tr>
                        <td>
                          <div style="font-weight:bold">Hotel Facilities</div>
                        </td>
                      </tr>
                      <tr>
                        <td>
                          <div style="height:70px; overflow:hidden">
                            <xsl:value-of select="Story/Desc_Hotel_Facilities"/>
                          </div>
                        </td>
                      </tr>
                      <tr>
                        <td>
                          <div style="font-weight:bold; margin-top:5px;">Guest Rooms</div>
                        </td>
                      </tr>
                      <tr>
                        <td>
                          <div style="height:70px; overflow:hidden">
                            <xsl:value-of select="Story/Desc_Guest_Rooms"/>
                          </div>
                        </td>
                      </tr>
                      <tr>
                        <td>
                          <div style="font-weight:bold; margin-top:5px; font-size:14px">
                            From <xsl:value-of select="$pound"/> <xsl:value-of select="Story/Price" /> per person per night
                          </div>
                          <div style="font-size:smaller">
                            <xsl:value-of select="Story/Desc_Price_description"/>
                          </div>
                        </td>
                      </tr>
                      <tr>
                      </tr>
                      <td>
                        <table style="padding-top:10px;">
                          <tr>
                            <td>
                              <a href="#">
                                <img src="enquiry.gif" title="email us" alt="email us" border="0" />
                              </a>
                            </td>
                            <td>
                              <a href="#">
                                <img src="branch.gif" title="find a branch" alt="find a branch" border="0" />
                              </a>
                            </td>
                          </tr>
                        </table>
                      </td>
                    </table>
                  </td>
                </tr>
              </table>
            </div>
          </td>
        </tr>
      </table>
    </div>

  </xsl:template>


  <xsl:template name="navigation">
    <div>
      <a>
      <xsl:attribute name="href">
          <xsl:text>?first=</xsl:text>
          <xsl:value-of select="$first - $size"/>
          <xsl:text>&amp;size=</xsl:text>
          <xsl:value-of select="$size"/>
        </xsl:attribute>
        <xsl:text>&lt; previous</xsl:text>
      </a>
      <xsl:text>   </xsl:text>
      <xsl:for-each select="Product[position() mod $size = 1  and (translate(normalize-space(Story/Desc_Destinations), 'AZERTYUIOPQSDFGHJKLMWXCVBN', 'azertyuiopqsdfghjklmwxcvbn') = translate(normalize-space($DestToSelect), 'AZERTYUIOPQSDFGHJKLMWXCVBN', 'azertyuiopqsdfghjklmwxcvbn'))]">
        <xsl:variable name="pos" select="position()"/>
        <xsl:variable name="this-start" select="1 + ($pos - 1) * $size"/>
        <xsl:choose>
          <xsl:when test="$this-start &lt;= $first and $first &lt; $this-start + $size">
            <span>
              <xsl:value-of select="$pos"/>
            </span>
          </xsl:when>
          <xsl:otherwise>
            <a>
              <xsl:attribute name="href">
                <xsl:text>?first=</xsl:text>
                <xsl:value-of select="$this-start"/>
                <xsl:text>&amp;size=</xsl:text>
                <xsl:value-of select="$size"/>
              </xsl:attribute>
              <xsl:value-of select="$pos"/>
            </a>
          </xsl:otherwise>
        </xsl:choose>
        <xsl:text>   </xsl:text>
      </xsl:for-each>
      <a>
        <xsl:attribute name="href">
          <xsl:text>?first=</xsl:text>
          <xsl:value-of select="$first + $size"/>
          <xsl:text>&amp;size=</xsl:text>
          <xsl:value-of select="$size"/>
        </xsl:attribute>
        <xsl:text>next &gt;</xsl:text>
      </a>
    </div>
  </xsl:template>
</xsl:stylesheet>

Open in new window

0
Cloud Class® Course: Microsoft Windows 7 Basic

This introductory course to Windows 7 environment will teach you about working with the Windows operating system. You will learn about basic functions including start menu; the desktop; managing files, folders, and libraries.

 
help-is-neededAuthor Commented:
Hi Gertone,

Thanks, i'll try replacing that code.
Will I also need to replace the pagination links that are created in the navigation template?

Thanks
0
 
Geert BormansInformation ArchitectCommented:
Well, it strikes me that you don't have the filtering added correctly to the navigation, so it is wrong as it currently is anyway

      <xsl:for-each select="Product[position() mod $size = 1  and (translate(normalize-space(Story/Desc_Destinations), 'AZERTYUIOPQSDFGHJKLMWXCVBN', 'azertyuiopqsdfghjklmwxcvbn') = translate(normalize-space($DestToSelect), 'AZERTYUIOPQSDFGHJKLMWXCVBN', 'azertyuiopqsdfghjklmwxcvbn'))]">

should be
      <xsl:for-each select="Product[(translate(normalize-space(Story/Desc_Destinations), 'AZERTYUIOPQSDFGHJKLMWXCVBN', 'azertyuiopqsdfghjklmwxcvbn') = translate(normalize-space($DestToSelect), 'AZERTYUIOPQSDFGHJKLMWXCVBN', 'azertyuiopqsdfghjklmwxcvbn'))][position() mod $size = 1]">
I guess

Still, all would be much easier if you emulated a two step in one stylesheet
You can do so if you can use node-set extensibility one way or another.
But that is processor depending,
so again, if you can figure out what the processor is, you can improve this code dramatically
If you don't do that for now, do that for later maintenance
0
 
help-is-neededAuthor Commented:
Hi Gertone,

Im just asking the server guys now to see if any of them know for me, thanks.

Will I need to amend the way I build the previous and next pagination buttons also?

Thanks
0
 
Geert BormansInformation ArchitectCommented:
previous and next only depend on the start point, so that would be OK, I guess



In case the server guys don't know

sneak this in your XSLT
<xsl:value-of select="system-property('xsl:version')" />//
<xsl:value-of select="system-property('xsl:vendor')" />//
<xsl:value-of select="system-property('xsl:vendor-url')" />

and you will find the information in the result
0
 
help-is-neededAuthor Commented:
Ok, i'll pop that in there today and upload it and let you know what comes back.

My final pagination questions is, how do I stop the next > link appearing if there are no more pages to scroll through.

I have it working for < prev as I have done a choose statement that checks to see if $first = 1, but not sure how to do it when it gets to the last record.

I'll open a new thread with the xsl version so you can get these points for the help you have already provided.

Thanks
0
 
Geert BormansInformation ArchitectCommented:
for last record you need to count the filtered records, not all records
0
 
help-is-neededAuthor Commented:
Thanks, got it.
Also, here is what I got back from the XSLT processor code:
1 // James Clark // http://www.jclark.com/

Open source processor by James Clark.
0
 
Geert BormansInformation ArchitectCommented:
well, that is a very old processor ("XT" it is)
I have never seen it used in production before.

It is the old processor James Clark wrote to test the XSLT specification (he is the author of version 1)
I never realised that people would use it in production

But I just checked, it supports xt:node-set, so you will get away with a two step
I have to go now.
I will download XT later (it must be the single one processor I don't have on my machine :-) and make a test example
for an XSLT twostep
that will likely be after the weekend
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.