Creating vertical multilevel navigation for umbraco XSLT - xslt

I'm trying to create a vertical multilevel nav for Umbraco using XSLT, that will add nested lists automatically. Currently I have had to keep adding each nested list manually into the XSLT (which is not good practice).
I've created the following menu but I need help as it's not creating the nest lists properly:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp " "> ]>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxml="urn:schemas-microsoft-com:xslt"
xmlns:umbraco.library="urn:umbraco.library"
exclude-result-prefixes="msxml umbraco.library">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:param name="currentPage"/>
<xsl:template match="/">
<xsl:variable name="level1" select="$currentPage/ancestor-or-self::* [#level = 2 and string(umbracoNaviHide) != '1' and string(hideFromSideNavigation) != '1']" />
<xsl:variable name="level" select="2"/>
<div class="subnav">
<!-- LEVEL 1 -->
<p><xsl:value-of select="$level1/#nodeName"/></p>
<ul>
<xsl:call-template name="drawNodes">
<xsl:with-param name="parent" select="$currentPage/ancestor-or-self::* [#isDoc][#level=2]"/>
</xsl:call-template>
</ul>
</div>
</xsl:template>
<xsl:template name="drawNodes">
<xsl:param name="parent"/>
<xsl:for-each select="$parent/ancestor-or-self::* [#level=2]/* [#isDoc and string(umbracoNaviHide) != '1' and string(#template) != '0']">
<li>
<xsl:if test="descendant-or-self::*[#id = $currentPage/#id]">
<xsl:attribute name="class">current</xsl:attribute>
</xsl:if>
<xsl:if test="count(./* [#isDoc and string(umbracoNaviHide) != '1' and string(#template) != '0']) = 0">
<a href="{umbraco.library:NiceUrl(#id)}">
<xsl:value-of select="#nodeName"/>
</a>
</xsl:if>
<xsl:if test="count(./* [#isDoc and string(umbracoNaviHide) != '1' and string(#template) != '0']) > 0">
<a href="{umbraco.library:NiceUrl(#id)}">
<xsl:value-of select="#nodeName"/>
</a>
<ul>
<xsl:choose>
<xsl:when test="./umbracoNaviHide != '1'">
<li>
<xsl:if test="descendant-or-self::*[#id = $currentPage/#id]">
<xsl:attribute name="class">current</xsl:attribute>
</xsl:if>
<a href="{umbraco.library:NiceUrl(#id)}">
<xsl:value-of select="#nodeName"/>
</a>
</li>
</xsl:when>
</xsl:choose>
<xsl:call-template name="drawNodes">
<xsl:with-param name="parent" select="."/>
</xsl:call-template>
</ul>
</xsl:if>
</li>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Here's manual added nested lists XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp " "> ]>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxml="urn:schemas-microsoft-com:xslt"
xmlns:umbraco.library="urn:umbraco.library"
exclude-result-prefixes="msxml umbraco.library">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:param name="currentPage"/>
<xsl:template match="/">
<xsl:variable name="level1" select="$currentPage/ancestor-or-self::* [#level = 2 and string(umbracoNaviHide) != '1' and string(hideFromSideNavigation) != '1']" />
<xsl:variable name="level" select="2"/>
<div class="subnav">
<!-- LEVEL 1 -->
<p><xsl:value-of select="$level1/#nodeName"/></p>
<!-- LEVEL 2 -->
<ul>
<xsl:for-each select="$currentPage/ancestor-or-self::* [#level=$level]/* [#isDoc and string(umbracoNaviHide) != '1' and string(#template) != '0']">
<li>
<xsl:if test="descendant-or-self::*[#id = $currentPage/#id]">
<xsl:attribute name="class">current</xsl:attribute>
</xsl:if>
<a href="{umbraco.library:NiceUrl(#id)}">
<xsl:value-of select="#nodeName"/>
</a>
<!-- LEVEL 3 if any more nodes are Visible -->
<xsl:if test="*[#isDoc][not(umbracoNaviHide = 1)]">
<ul>
<xsl:for-each select="./* [#isDoc and string(umbracoNaviHide) != '1' and string(#template) != '0']">
<li>
<xsl:if test="descendant-or-self::*[#id = $currentPage/#id]">
<xsl:attribute name="class">current</xsl:attribute>
</xsl:if>
<a href="{umbraco.library:NiceUrl(#id)}">
<xsl:value-of select="#nodeName"/>
</a>
<!-- LEVEL 4 if any more nodes are Visible -->
<xsl:if test="*[#isDoc][not(umbracoNaviHide = 1)]">
<ul>
<xsl:for-each select="./* [#isDoc and string(umbracoNaviHide) != '1' and string(#template) != '0']">
<li>
<xsl:if test="descendant-or-self::*[#id = $currentPage/#id]">
<xsl:attribute name="class">current</xsl:attribute>
</xsl:if>
<a href="{umbraco.library:NiceUrl(#id)}">
<xsl:value-of select="#nodeName"/>
</a>
<!-- LEVEL 5 if any more nodes are Visible -->
<xsl:if test="*[#isDoc][not(umbracoNaviHide = 1)]">
<ul>
<xsl:for-each select="./* [#isDoc and string(umbracoNaviHide) != '1' and string(#template) != '0']">
<li>
<xsl:if test="descendant-or-self::*[#id = $currentPage/#id]">
<xsl:attribute name="class">current</xsl:attribute>
</xsl:if>
<a href="{umbraco.library:NiceUrl(#id)}">
<xsl:value-of select="#nodeName"/>
</a>
</li>
</xsl:for-each>
</ul>
</xsl:if>
</li>
</xsl:for-each>
</ul>
</xsl:if>
</li>
</xsl:for-each>
</ul>
</xsl:if>
</li>
</xsl:for-each>
</ul>
</div>
</xsl:template>
</xsl:stylesheet>
Can anyone suggest a solution?

After posting the same question on the Umbraco forum, I received the following link:
http://our.umbraco.org/projects/website-utilities/cogworks-flexible-navigation
It's perfect and will hopefully help others. A great package that allows for both vertical and horizontal navigation types.

Related

convert xml to html list with xslt

I have a xslt code to convert an xml file to html list. The input and output samples are as follows:
Input:
<Beverages>
<Water/>
<Coffee/>
<Tea>
<BlackTea/>
<WhiteTea id="cti" value="ctv" >Camomile Tea</WhiteTea>
<GreenTea id="gti" value="gtv">
<Sencha/>
<Gyokuro/>
<Matcha/>
<PiLoChun/>
</GreenTea>
</Tea>
</Beverages>
and the Output:
<ul>
<li>
<span class="caret"><Beverages></span>
<ul class="nested">
<li><span><Water/></span></li>
<li><span><Coffee/></span></li>
<li>
<span class="caret"><Tea></span>
<ul class="nested">
<li><span><BlackTea/></span></li>
<li><span><WhiteTea id="cti" value="ctv"></span>Camomile Tea<span></WhiteTea></span></li>
<li>
<span><GreenTea id="gti" value="gtv"></span>
<ul class="nested">
<li><span><Sencha/></span></li>
<li><span><Gyokuro/></span></li>
<li><span><Matcha/></span></li>
<li><span><PiLoChun/></span></li>
</ul>
<span></GreenTea></span>
</li>
</ul>
</li>
</ul>
<span></Beverages></span>
</li>
</ul>
Here is my xslt but it is not exactly the same as what I want:
<xsl:template match="/">
<ul><xsl:apply-templates/></ul>
</xsl:template>
<xsl:template match="*">
<li> <span class="caret"><xsl:value-of select="concat('<',name())" />
<xsl:for-each select="#*">
<xsl:value-of select="concat(' ',name())"/>=<xsl:value-of select="concat('"',.,'"')" />
</xsl:for-each>></span>
<xsl:if test="text()">
<xsl:apply-templates select="text()" />
</xsl:if>
<xsl:if test="*">
<ul class="nested"><xsl:apply-templates/></ul>
</xsl:if>
<span><xsl:value-of select="concat('<','/' ,name() , '>')" /></span></li>
</xsl:template>
The problem is that this code can not differentiate between parent elements and non parent element. for parent elements we need to add class="caret" attribute, but for non parent elements we shouldn't add this class.
This should work for you.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<ul>
<xsl:apply-templates/>
</ul>
</xsl:template>
<xsl:template match="*">
<li>
<span>
<xsl:if test="*">
<xsl:attribute name="class">
<xsl:value-of select="'caret'"/>
</xsl:attribute>
</xsl:if>
<xsl:value-of select="concat('<',name())"/>
<xsl:for-each select="#*">
<xsl:value-of select="concat(' ', name(), '=', '"', ., '"')"/>
</xsl:for-each>
<xsl:choose>
<xsl:when test="text() or *">
<xsl:value-of select="'>'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'\>'"/>
</xsl:otherwise>
</xsl:choose>
</span>
<xsl:if test="text()">
<xsl:value-of select="text()"/>
</xsl:if>
<xsl:if test="*">
<ul class="nested">
<xsl:apply-templates/>
</ul>
</xsl:if>
<xsl:if test="text() or *">
<span>
<xsl:value-of select="concat('<','/' ,name() , '>')"/>
</span>
</xsl:if>
</li>
</xsl:template>
</xsl:stylesheet>

insert div after X li

I have an xslt navigation, which I want to break into 2 columns, so that after every 6 "li" it creates a new "div"...
I would like to output to be like this:
<ul>
<div class="col">
<li>link</li>
<li>link</li>
<li>link</li>
<li>link</li>
<li>link</li>
<li>link</li>
</div>
<div class="col">
<li>link</li>
<li>link</li>
<li>link</li>
<li>link</li>
<li>link</li>
<li>link</li>
</div>
</ul>
But not quite sure how to do this
My XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes" encoding="utf-8" />
<xsl:param name="html-content-type" />
<xsl:template match="/NavigationTree">
<xsl:if test="count(//Page) > 0">
<ul>
<xsl:apply-templates select="Page">
<xsl:with-param name="depth" select="1"/>
</xsl:apply-templates>
</ul>
</xsl:if>
</xsl:template>
<xsl:template match="//Page">
<xsl:param name="depth"/>
<li>
<xsl:attribute name="class">
<xsl:if test="#InPath='True'">inpath </xsl:if>
<xsl:if test="position() = 1">firstitem </xsl:if>
<xsl:if test="position() = count(//Page)">lastitem </xsl:if>
<xsl:if test="#Active='True'">selected</xsl:if>
</xsl:attribute>
<a>
<xsl:attribute name="class">
<xsl:if test="#InPath='True'">inpath </xsl:if>
<xsl:if test="position() = 1">firstitem </xsl:if>
<xsl:if test="position() = count(//Page)">lastitem </xsl:if>
<xsl:if test="#Active='True'">current</xsl:if>
</xsl:attribute>
<xsl:attribute name="href"><xsl:value-of select="#FriendlyHref" disable-output-escaping="yes"/></xsl:attribute>
<xsl:value-of select="#MenuText" disable-output-escaping="yes"/>
</a>
<div class="icon">
<xsl:text disable-output-escaping="yes"><![CDATA[<!--dsfdsfdsf-->]]></xsl:text>
</div>
<xsl:if test="count(Page)">
<ul class="M{#AbsoluteLevel}">
<xsl:apply-templates select="Page">
<xsl:with-param name="depth" select="$depth+1"/>
</xsl:apply-templates>
</ul>
</xsl:if>
</li>
</xsl:template>
</xsl:stylesheet>
A way to do it would be to have a template that matches every 6 Page element:
<xsl:template match="//Page[position() mod 6 = 1]">
<div>
<xsl:apply-templates select="." mode="SecondLevel"/>
<xsl:apply-templates select="following-sibling::Page[position()<6]" mode="SecondLevel"/>
</div>
</xsl:template>
generating the div and applying a second-level template to the current element and its 5 following sibling. The second level template is the one you already have - with an added mode:
<xsl:template match="Page" mode="SecondLevel">
<li>
<xsl:attribute name="class">
<xsl:if test="#InPath='True'">inpath </xsl:if>
<xsl:if test="position() = 1">firstitem </xsl:if>
<xsl:if test="position() = count(//Page)">lastitem </xsl:if>
<xsl:if test="#Active='True'">selected</xsl:if>
</xsl:attribute>
<a>
<xsl:attribute name="class">
<xsl:if test="#InPath='True'">inpath </xsl:if>
<xsl:if test="position() = 1">firstitem </xsl:if>
<xsl:if test="position() = count(//Page)">lastitem </xsl:if>
<xsl:if test="#Active='True'">current</xsl:if>
</xsl:attribute>
<xsl:attribute name="href">
<xsl:value-of select="#FriendlyHref" disable-output-escaping="yes"/>
</xsl:attribute>
<xsl:value-of select="#MenuText" disable-output-escaping="yes"/>
</a>
<div class="icon">
<xsl:text disable-output-escaping="yes"><![CDATA[<!--dsfdsfdsf-->]]></xsl:text>
</div>
</li>
</xsl:template>

How to display sitemap/navigation for a site using xslt?

I have a website that has pages and subpages as in the image attached.
Some of the subpages belong to First pagge(About Patient Direct), they have setted 'do not show in menu'.
All right, I want to make an xslt file that will generate an html content like this:
Menu Item 1 (including Home page - About Patient Direct)
-submenu page 1 1
Menu Item 2 (including Home page - About Patient Direct)
-submenu page 2 1
-submenu page 2 2
How can I do that?
This is what I have so far
<?xml version="1.0" encoding="UTF-8"?>
]>
<xsl:output method="xml" omit-xml-declaration="yes" />
<xsl:param name="currentPage"/>
<!-- Input the documenttype you want here -->
<xsl:variable name="level" select="1"/>
<xsl:template match="/">
<xsl:if test="$currentPage/#id = $currentPage/ancestor-or-self::* [#level=$level]/#id">
<div class="column">
<h1>
<a href="#">
Home Page - I don't know what to write here
</a>
</h1>
</div>
</xsl:if>
<xsl:for-each select="$currentPage/ancestor-or-self::* [#level=$level]/* [#isDoc and string(umbracoNaviHide) != '1']">
<div class="column">
<h1>
<xsl:choose>
<xsl:when test="name() = 'Link'">
<a href="{current()/linkUrl}" target="_blank">
<xsl:value-of select="#nodeName" />
</a>
</xsl:when>
<xsl:otherwise>
<a href="{umbraco.library:NiceUrl(#id)}">
<xsl:value-of select="#nodeName" />
</a>
</xsl:otherwise>
</xsl:choose>
</h1>
</div>
</xsl:for-each>
</xsl:template>
I have also opened a discussion on http://our.umbraco.org/forum/developers/xslt/33326-How-to-display-sitemapnavigation-for-a-site-using-xslt
I have finally succeeded to do what I have been looking for. Here is the code for those who might be looking for same functionality
<?xml version="1.0" encoding="UTF-8"?>
]>
<xsl:template name="menu">
<xsl:param name="level"/>
<xsl:variable name="RootNode" select="umbraco.library:GetXmlNodeById(1050)" />
<div class="column">
<h1>
<a href="{umbraco.library:NiceUrl($RootNode/#id)}" style="width:200px;">
<xsl:value-of select="$RootNode/#nodeName"/>
</a>
</h1>
<xsl:call-template name="submenu_Homepage">
</xsl:call-template>
</div>
<xsl:if test="count($currentPage/ancestor-or-self::* [#level=$level]/* [#isDoc and string(umbracoNaviHide) != '1']) > '0'">
<xsl:for-each select="$currentPage/ancestor-or-self::* [#level=$level]/* [#isDoc and string(umbracoNaviHide) != '1']">
<div class="column">
<h1>
<xsl:choose>
<xsl:when test="name() = 'Link'">
<a href="{current()/linkUrl}" target="_blank">
<xsl:value-of select="#nodeName" />
</a>
</xsl:when>
<xsl:otherwise>
<a href="{umbraco.library:NiceUrl(#id)}">
<xsl:value-of select="#nodeName" />
</a>
</xsl:otherwise>
</xsl:choose>
</h1>
<xsl:if test="count(current()/* [#isDoc and string(umbracoNaviHide) != '1']) > '0'">
<xsl:call-template name="submenu">
<xsl:with-param name="level" select="$level+1"/>
</xsl:call-template>
</xsl:if>
</div>
</xsl:for-each>
</xsl:if>
</xsl:template>
<xsl:template name="submenu">
<xsl:param name="level"/>
<ul class="level_{#level}">
<xsl:for-each select="current()/*[#isDoc and string(umbracoNaviHide) != '1']">
<li>
<xsl:if test="position() != last()">
<xsl:attribute name="class">bottom_border</xsl:attribute>
</xsl:if>
<a href="{umbraco.library:NiceUrl(#id)}">
<xsl:value-of select="#nodeName"/>
</a>
<!--case when we have third menu level-->
<xsl:if test="count(current()/* [#isDoc and string(umbracoNaviHide) != '1']) > '0'">
<xsl:call-template name="submenu">
<xsl:with-param name="level" select="$level+1"/>
</xsl:call-template>
</xsl:if>
</li>
</xsl:for-each>
</ul>
</xsl:template>
<xsl:template name="submenu_Homepage">
<ul>
<xsl:for-each select="$currentPage/ancestor-or-self::*/* [#isDoc and string(umbracoNaviHide) = '1']">
<li>
<xsl:if test="position() != last()">
<xsl:attribute name="class">bottom_border</xsl:attribute>
</xsl:if>
<xsl:choose>
<xsl:when test="name() = 'Link'">
<a href="{current()/linkUrl}" target="_blank">
<xsl:value-of select="#nodeName" />
</a>
</xsl:when>
<xsl:otherwise>
<a href="{umbraco.library:NiceUrl(#id)}">
<xsl:value-of select="#nodeName" />
</a>
</xsl:otherwise>
</xsl:choose>
</li>
</xsl:for-each>
</ul>
</xsl:template>

A variable passed on to a template is tampered with

<xsl:param name="currentPage"/>
<xsl:param name="group-size" select="'2'" />
<xsl:template match="/">
<xsl:variable name="userBlogSource" select="umbraco.library:GetXmlNodeById(umbraco.library:GetDictionaryItem('WeblogNode'))/node [string(data [#alias='umbracoNaviHide']) != '1' and data[#alias='author'] = $currentPage/#id]" />
<xsl:for-each select="$userBlogSource">
<xsl:sort select="data[#alias='dato']" order="descending" />
</xsl:for-each>
<xsl:if test="count($userBlogSource) > 0">
<h3><xsl:value-of select="umbraco.library:GetDictionaryItem('BlogpostsWrittenBy')"/> <xsl:value-of select="$currentPage/#nodeName" />:</h3>
<xsl:apply-templates select="$userBlogSource[(position() mod $group-size) = 1]" />
<ul>
<xsl:for-each select="$userBlogSource">
<li>
<a rel="bookmark" href="{umbraco.library:NiceUrl(#id)}" title="{#nodeName}">
<xsl:value-of select="#nodeName" />
</a>
</li>
</xsl:for-each>
</ul>
</xsl:if>
</xsl:template>
<xsl:template match="node">
<xsl:variable name="postnum" select="position()" />
<div class="weblog-posts-wrap">
<ul>
<xsl:for-each select=". | following-sibling::node[position() < $group-size]">
<li>
<a rel="bookmark" href="{umbraco.library:NiceUrl(#id)}" title="{#nodeName}">
<xsl:value-of select="#nodeName" />
</a>
</li>
</xsl:for-each>
</ul>
</div>
</xsl:template>
When I check the count of $userBlogSource it contains three elements. When I attempt to print the in a regular XSLT for loop it does print the correct elements. But when the variable is passed to the second template matching node, the content is suddenly different. Instead of the three nodes it should contain, it contains 4 nodes by entirely different authors.
Any idea of what I may be doing wrong?

How to implement sorting using xslt on href

I am using xslt and I want to implement sorting on my href link.
below is the xslt part where I need to implement sorting.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:tlink="urn:TridionLinking" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:utils="urn:XSLTExtensions" exclude-result-prefixes="xsl xlink tlink msxsl utils">
<xsl:output method="xml" version="1.0" encoding="UTF-8" omit-xml-declaration="yes" />
<!--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Title: View All the Destinations XHTML
Description: Render view all the destinations control
Author: Manoj Singh
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-->
<xsl:include href="dynamic_linking.xslt"/>
<!-- Translations are still loaded here because of XHTML content, research a way around that -->
<xsl:key name="kCityById" match="city" use="#id"/>
<xsl:variable name="vLocations" select="document(concat($publicationPath, /list/resources/#location))/list"/>
<xsl:variable name="destination" select="/list"/>
<xsl:param name="publicationPath"/>
<xsl:param name="pubURL"/>
<xsl:param name="pageURL"/>
<xsl:param name="region"/>
<xsl:param name="country"/>
<!-- offset controls the starting position of the results to show -->
<xsl:param name="offset">0</xsl:param>
<!-- blockSize controls how many results to show on a single page -->
<xsl:param name="blockSize" select="15" />
<!-- Amount of page links to show by default -->
<xsl:param name="pagesShown">20</xsl:param>
<xsl:variable name="totalHits" select="count(/list/destination[contains(concat($pubURL,#url),substring-before($pageURL,'/index.aspx'))])" />
<xsl:template name="calcStart">
<xsl:choose>
<xsl:when test="$offset = 0">1</xsl:when>
<xsl:otherwise>
<xsl:value-of select="($offset * $blockSize) + 1"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="calcEnd">
<xsl:choose>
<xsl:when test="(($offset + 1) * $blockSize) > $totalHits">
<xsl:value-of select="$totalHits"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="($offset + 1) * $blockSize"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="pageNavigation">
<xsl:param name="pageCount"/>
<xsl:param name="currPage"/>
<xsl:param name="showPages">
<xsl:choose>
<xsl:when test="$pagesShown > $pageCount">
<xsl:value-of select="$pageCount"/>
</xsl:when>
<xsl:when test="($pagesShown mod 2) = 0">
<xsl:value-of select="$pagesShown"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$pagesShown + 1"/>
</xsl:otherwise>
</xsl:choose>
</xsl:param>
<xsl:param name="currEntry" select="1"/>
<xsl:param name="offset">
<xsl:choose>
<xsl:when test="($currPage < $showPages) or ($pageCount = 1)">0</xsl:when>
<xsl:when test="$currPage > ($pageCount - $showPages + 1)">
<xsl:value-of select="$pageCount - $showPages"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$currPage - ($showPages div 2) - 1"/>
</xsl:otherwise>
</xsl:choose>
</xsl:param>
<!-- Header Processing -->
<xsl:if test="$currEntry = 1">
<xsl:if test="($pageCount > $showPages) and ($currPage >= $showPages)">
<li>... </li>
</xsl:if>
</xsl:if>
<xsl:if test="not ($currEntry > $showPages)">
<li>
<xsl:choose>
<xsl:when test="($currEntry + $offset) = $currPage">
<strong class="thisPage">
<xsl:value-of select="$currEntry + $offset"/>
</strong>
</xsl:when>
<xsl:otherwise>
<a href="{utils:GetHashedUrl(concat($pageURL,'?offset=',$currEntry + $offset - 1,'&blockSize=',$blockSize,'&pagesShown=',$pagesShown))}">
<xsl:value-of select="$currEntry + $offset"/>
</a>
</xsl:otherwise>
</xsl:choose>
</li>
<xsl:if test="not ($currEntry >= $showPages)">
<li class="separatorLine">|</li>
</xsl:if>
<xsl:call-template name="pageNavigation">
<xsl:with-param name="pageCount" select="$pageCount"/>
<xsl:with-param name="currPage" select="$currPage"/>
<xsl:with-param name="showPages" select="$showPages"/>
<xsl:with-param name="currEntry" select="$currEntry + 1"/>
<xsl:with-param name="offset" select="$offset"/>
</xsl:call-template>
</xsl:if>
<!-- Footer Processing -->
<xsl:if test="$currEntry = 1">
<xsl:if test="($pageCount > $showPages) and (($pageCount - $currPage + 1) >= $showPages)">
<li> ...</li>
</xsl:if>
</xsl:if>
</xsl:template>
<xsl:template name="displayPageNavigation">
<div class="continueBar">
<div class="continueBarLeft">
<xsl:variable name="displayStart">
<xsl:call-template name="calcStart"/>
</xsl:variable>
<xsl:variable name="displayEnd">
<xsl:call-template name="calcEnd"/>
</xsl:variable>
<strong>
<xsl:value-of select="utils:TextFormatted('DisplayingDestinations2Arg', concat($displayStart, '-', $displayEnd), $totalHits)"/>
</strong>
</div>
<div class="continueBarRight">
<ul class="paginationLinks">
<!-- Show a back button when available -->
<xsl:choose>
<xsl:when test="$offset > 0">
<li class="noBorder first">
<a class="iconButtonBackBar" href="{$pageURL}?offset={$offset - 1}&blockSize={$blockSize}&pagesShown={$pagesShown}">
<xsl:text disable-output-escaping="yes">&nbsp;</xsl:text>
</a>
</li>
</xsl:when>
<xsl:otherwise>
<li class="noBorder first">
<span class="iconButtonBackBarOff">
<xsl:text disable-output-escaping="yes">&nbsp;</xsl:text>
</span>
</li>
</xsl:otherwise>
</xsl:choose>
<!-- Output the page navigation links -->
<xsl:call-template name="pageNavigation">
<xsl:with-param name="pageCount">
<xsl:choose>
<xsl:when test="$blockSize >= $totalHits">1</xsl:when>
<xsl:when test="($totalHits mod $blockSize) != 0">
<xsl:value-of select="ceiling($totalHits div $blockSize)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$totalHits div $blockSize"/>
</xsl:otherwise>
</xsl:choose>
</xsl:with-param>
<xsl:with-param name="currPage" select="$offset + 1"/>
</xsl:call-template>
<!-- Show a next button when available -->
<xsl:choose>
<xsl:when test="(($offset + 1) * $blockSize) > $totalHits">
<li class="last">
<span class="iconButtonForwardBarOff">
<xsl:text disable-output-escaping="yes">&nbsp;</xsl:text>
</span>
</li>
</xsl:when>
<xsl:otherwise>
<li class="last">
<a class="iconButtonForwardBar" href="{$pageURL}?offset={$offset + 1}&blockSize={$blockSize}&pagesShown={$pagesShown}">
<xsl:text disable-output-escaping="yes">&nbsp;</xsl:text>
</a>
</li>
</xsl:otherwise>
</xsl:choose>
</ul>
</div>
<div class="clearBoth">
<xsl:comment/>
</div>
</div>
</xsl:template>
<!-- root match -->
<xsl:template match="/list">
<!--<xsl:value-of select="$publicationPath"/>-->
<div class="brownBarContainer">
<div class="brownBar">
All Destinations
</div>
</div>
<table width="100%" cellspacing="0" cellpadding="0" border="0" class="displayTable">
<tbody>
<tr>
<th scope="col" class="first sortSelected">
<div class="thPadding">
<xsl:element name="a">
<xsl:attribute name="href"></xsl:attribute>
<xsl:attribute name="class">iconDownSortArrow</xsl:attribute>
</xsl:element>Destination
</div>
</th>
<th scope="col" class="sortHover">
<div class="thPadding">
<xsl:element name="a">
<xsl:attribute name="href"></xsl:attribute>
<xsl:attribute name="class">iconSortArrowOff</xsl:attribute>
</xsl:element>Country
</div>
</th>
<th scope="col" class="sortHover">
<div class="thPadding">
<xsl:element name="a">
<xsl:attribute name="href"></xsl:attribute>
<xsl:attribute name="class">iconSortArrowOff</xsl:attribute>
</xsl:element>Region
</div>
</th>
</tr>
<xsl:choose>
<xsl:when test="$region='' and $country=''">
<xsl:apply-templates select="destination">
<xsl:sort select="#title" order="ascending" />
</xsl:apply-templates>
</xsl:when>
<xsl:when test="$country!=''">
<xsl:apply-templates select="destination[city/#id=$vLocations/region/country[#id=$country]/city/#id]">
<xsl:sort select="#title" order="ascending" />
</xsl:apply-templates>
</xsl:when>
<xsl:when test="$region!=''">
<xsl:apply-templates select="destination[city/#id=$vLocations/region[#id=$region]/country/city/#id]">
<xsl:sort select="#title" order="ascending" />
</xsl:apply-templates>
</xsl:when>
</xsl:choose>
</tbody>
</table>
<div class="horRuleWhite">
<hr/>
</div>
<xsl:call-template name="displayPageNavigation" />
</xsl:template>
<xsl:template match="text()"/>
<xsl:template match="destination">
<xsl:variable name="vReverseURL">
<xsl:call-template name="reverse">
<xsl:with-param name="string" select="#url"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="vCountryURL">
<xsl:call-template name="reverse">
<xsl:with-param name="string" select="substring-after($vReverseURL,'/')"/>
</xsl:call-template>
<xsl:text>/index.aspx</xsl:text>
</xsl:variable>
<xsl:variable name="vRegionURL">
<xsl:call-template name="reverse">
<xsl:with-param name="string" select="substring-after(substring-after($vReverseURL,'/'),'/')"/>
</xsl:call-template>
<xsl:text>/index.aspx</xsl:text>
</xsl:variable>
<xsl:variable name="current" select="."/>
<xsl:for-each select="$vLocations">
<tr>
<td class="detail first">
<a class="arrowSmallFront" href="{$current/#url}">
<xsl:value-of select="$current/#title"/>
</a>
</td>
<td class="detail noLeftBorder">
<a class="arrowSmallFront" href="{$vCountryURL}">
<xsl:value-of select="key('kCityById',$current/city/#id)/../#name"/>
</a>
</td>
<td class="detail noLeftBorder">
<a class="arrowSmallFront" href="{$vRegionURL}">
<xsl:value-of select="key('kCityById',$current/city/#id)/../../#name"/>
</a>
</td>
</tr>
</xsl:for-each>
</xsl:template>
<xsl:template name="reverse">
<xsl:param name="string" select="''"/>
<xsl:if test="$string != ''">
<xsl:call-template name="reverse">
<xsl:with-param name="string" select="substring($string,2)"/>
</xsl:call-template>
<xsl:value-of select="substring($string,1,1)"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Now everything is working fine, however I want to implement sorting on the href link in above xslt.
<tr>
<th scope="col" class="first sortSelected">
<div class="thPadding">
<xsl:element name="a">
<xsl:attribute name="href"></xsl:attribute>
<xsl:attribute name="class">iconDownSortArrow</xsl:attribute>
</xsl:element>Destination
</div>
</th>
<th scope="col" class="sortHover">
<div class="thPadding">
<xsl:element name="a">
<xsl:attribute name="href"></xsl:attribute>
<xsl:attribute name="class">iconSortArrowOff</xsl:attribute>
</xsl:element>Country
</div>
</th>
<th scope="col" class="sortHover">
<div class="thPadding">
<xsl:element name="a">
<xsl:attribute name="href"></xsl:attribute>
<xsl:attribute name="class">iconSortArrowOff</xsl:attribute>
</xsl:element>Region
</div>
</th>
</tr>
1) Destinations.xml
<?xml version="1.0"?>
<list type="Destinations">
<resources location="include/xml/locations.xml">
<publication>481</publication>
</resources>
<destination id="594051" title="Sydney" url="/asiapacific/australia/sydney.aspx" >
<city id="192409" />
</destination>
<destination id="594088" title="Brisbane" url="/asiapacific/australia/brisbane.aspx" >
<city id="192397" />
</destination>
<destination id="594579" title="Dubai" url="/middleeast/uae/dubai.aspx" >
<city id="192855" />
</destination>
<destination id="594580" title="Abu Dhabi" url="/middleeast/uae/abudhabi.aspx" >
<city id="192851" />
</destination>
</list>
2) Locations.xml
<?xml version="1.0"?>
<list type="Locations">
<region id="192393" code="ASIA" name="Asia & the Pacific" shortname="Asia & the Pacific">
<country id="192395" code="AU" name="Australia" shortname="Australia">
<city id="192397" code="BNE" name="Brisbane" shortname="Brisbane">
<airport id="192399" code="BNE" name="Brisbane International Airport" shortname="Brisbane"></airport>
</city>
<city id="192409" code="SYD" name="Sydney" shortname="Sydney">
<airport id="192411" code="SYD" name="Kingsford Smith Airport" shortname="Sydney"></airport>
</city>
</country>
</region>
<region id="192847" code="MEAF" name="The Middle East & Africa" shortname="The Middle East & Africa">
<country id="192849" code="AE" name="United Arab Emirates" shortname="United Arab Emirates">
<city id="192851" code="AUH" name="Abu Dhabi" shortname="Abu Dhabi">
<airport id="192853" code="AUH" name="Abu Dhabi" shortname="Abu Dhabi"></airport>
</city>
<city id="192855" code="DXB" name="Dubai" shortname="Dubai">
<airport id="192857" code="DXB" name="Dubai International Airport" shortname="Dubai"></airport>
</city>
</country>
</region>
</list>
Please suggest!
Thanks.
Before each close tag </xsl:apply-templates> you need to include an <xsl:sort>, e.g.
<xsl:when test="$region='' and $country=''">
<xsl:apply-templates select="destination">
<xsl:sort select="#href" />
</xsl:apply-templates>
</xsl:when>
The above code assumes that #href is an attribute of the destination element, but that's just a guess, since you haven't told us where #href appears in the input. Unless I missed something.
If you need further help please post a sample of your input XML.
On second reading, I wonder if you mean that you want to sort based on which of the three a elements is clicked on? Please clarify, and edit your question to include a sample of your input XML.
OK, based on your comment it's clear that you want to sort based on whichever column the user clicked on last.
To expand on what Alejandro was saying, interactive behavior is outside the scope of XSLT. If you want XSLT to sort based on varying columns, you need to pass that column to the XSLT as an initial parameter. If the XSLT is running on the server, the whole page will reload when you change the sort order of the table. Do you want that?
For instant sorting you could call the XSLT within js on the client, but that's a bit hairy. Usually for interactive sorting, people just sort directly in javascript. Here are some tutorials and implementations:
http://www.javascripttoolbox.com/lib/table/
http://neil.fraser.name/software/tablesort/
http://dynamictable.com/