Note that there are some explanatory texts on larger screens.

plurals
  1. POMore concise / efficient XSLT
    primarykey
    data
    text
    <p>How can the XSLT transformation below be more concise? It works, but I still haven't been able to see the problem declaratively (being a relative XSLT novice), and feel this solution is a procedural &amp; rather verbose solution. I would like to see how someone with an intuitive feel for the declarative approach would solve / simplify it?</p> <p>The XSLT is used to construct a vertical navigation element that has three levels of depth. The navigation element expands/collapses depending on which node is selected. Css classes (active) are also applied depending on which level is selected.</p> <p>It takes 2 parameters, id and query_string. </p> <p>There is a special case node 'News' in the XML this acts upon - all descendent nodes from this node have the same id, so query_string is used to differentiate between them.</p> <p>Here is the XSLT</p> <pre><code>&lt;xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"&gt; &lt;xsl:output method="html" omit-xml-declaration="yes" indent="yes" /&gt; &lt;xsl:param name="id" select="'id:144016'"&gt;&lt;/xsl:param&gt; &lt;xsl:param name="query_string" select="'year=2012&amp;amp;month=12'"/&gt; &lt;xsl:template match="/"&gt; &lt;xsl:choose&gt; &lt;xsl:when test="//siteMapNode[@id=$id and @query_string=$query_string]"&gt; &lt;xsl:apply-templates select="//siteMapNode[@id=$id and @query_string=$query_string]/ancestor-or-self::*[@depth=1]" /&gt; &lt;/xsl:when&gt; &lt;xsl:when test="//siteMapNode[@id=$id]/ancestor::*[@depth=1]"&gt; &lt;xsl:apply-templates select="//siteMapNode[@id=$id]/ancestor-or-self::*[@depth=1]" /&gt; &lt;/xsl:when&gt; &lt;xsl:otherwise&gt; &lt;xsl:apply-templates select="//siteMapNode[@id=$id]" /&gt; &lt;/xsl:otherwise&gt; &lt;/xsl:choose&gt; &lt;/xsl:template&gt; &lt;xsl:template match="siteMapNode/siteMapNode/siteMapNode"&gt; &lt;xsl:variable name="matchidandyearpartofquery" select="count(self::node()[@id=$id and @query_string=substring($query_string, 1, 9)])" /&gt; &lt;xsl:variable name="matchid" select="count(self::node()[@id=$id])" /&gt; &lt;xsl:variable name="matchdescendentid" select="count(self::node()//*[@id=$id and @query_string=substring($query_string, 1, 9)])" /&gt; &lt;li&gt; &lt;xsl:if test="$matchidandyearpartofquery &amp;gt; 0 or $matchdescendentid &amp;gt; 0"&gt; &lt;xsl:attribute name="class"&gt; &lt;xsl:text&gt;active&lt;/xsl:text&gt; &lt;/xsl:attribute&gt; &lt;/xsl:if&gt; &lt;a&gt; &lt;xsl:attribute name="href"&gt; &lt;xsl:value-of select="@url" /&gt; &lt;/xsl:attribute&gt; &lt;xsl:value-of select="@title" /&gt; &lt;/a&gt; &lt;xsl:choose&gt; &lt;xsl:when test="self::node()[@id=$id and @query_string=substring($query_string, 1, 9)]"&gt; &lt;xsl:if test="./*"&gt; &lt;ul&gt; &lt;xsl:apply-templates select="siteMapNode"&gt; &lt;xsl:sort select="@month" data-type="number" order="descending"/&gt; &lt;/xsl:apply-templates&gt; &lt;/ul&gt; &lt;/xsl:if&gt; &lt;/xsl:when&gt; &lt;xsl:when test="self::node()//*[@id=$id and @query_string=substring($query_string, 1, 9)]"&gt; &lt;ul&gt; &lt;xsl:apply-templates select="siteMapNode"&gt; &lt;xsl:sort select="@month" data-type="number" order="descending"/&gt; &lt;/xsl:apply-templates&gt; &lt;/ul&gt; &lt;/xsl:when&gt; &lt;xsl:when test="self::node()[@id=$id]"&gt; &lt;xsl:if test="./*"&gt; &lt;xsl:if test="./*[not(@id=$id)]"&gt; &lt;ul&gt; &lt;xsl:apply-templates select="siteMapNode"&gt; &lt;xsl:sort select="@month" data-type="number" order="descending"/&gt; &lt;/xsl:apply-templates&gt; &lt;/ul&gt; &lt;/xsl:if&gt; &lt;/xsl:if&gt; &lt;/xsl:when&gt; &lt;xsl:when test="self::node()//*[@id=$id]"&gt; &lt;ul&gt; &lt;xsl:apply-templates select="siteMapNode"&gt; &lt;xsl:sort select="@month" data-type="number" order="descending"/&gt; &lt;/xsl:apply-templates&gt; &lt;/ul&gt; &lt;/xsl:when&gt; &lt;xsl:otherwise&gt; &lt;/xsl:otherwise&gt; &lt;/xsl:choose&gt; &lt;/li&gt; &lt;/xsl:template&gt; &lt;xsl:template match="siteMapNode/siteMapNode/siteMapNode/siteMapNode"&gt; &lt;xsl:variable name="matchidandyearpartofquery" select="count(self::node()[@id=$id and @query_string=$query_string])" /&gt; &lt;xsl:variable name="matchid" select="count(self::node()[@id=$id])" /&gt; &lt;xsl:variable name="matchdescendentid" select="count(self::node()//*[@id=$id and @query_string=substring($query_string, 1, 9)])" /&gt; &lt;li&gt; &lt;xsl:if test="$matchidandyearpartofquery &amp;gt; 0 or $matchdescendentid &amp;gt; 0"&gt; &lt;xsl:attribute name="class"&gt; &lt;xsl:text&gt;active icon-nav-left&lt;/xsl:text&gt; &lt;/xsl:attribute&gt; &lt;/xsl:if&gt; &lt;a&gt; &lt;xsl:attribute name="href"&gt; &lt;xsl:value-of select="@url" /&gt; &lt;/xsl:attribute&gt; &lt;xsl:value-of select="@title" /&gt; &lt;/a&gt; &lt;xsl:choose&gt; &lt;xsl:when test="self::node()[@id=$id and @query_string=$query_string]"&gt; &lt;xsl:if test="./*"&gt; &lt;ul&gt; &lt;xsl:apply-templates select="siteMapNode"&gt; &lt;xsl:sort select="@month" data-type="number" order="descending"/&gt; &lt;/xsl:apply-templates&gt; &lt;/ul&gt; &lt;/xsl:if&gt; &lt;/xsl:when&gt; &lt;xsl:when test="self::node()//*[@id=$id and @query_string=substring($query_string, 1, 9)]"&gt; &lt;ul&gt; &lt;xsl:apply-templates select="siteMapNode"&gt; &lt;xsl:sort select="@month" data-type="number" order="descending"/&gt; &lt;/xsl:apply-templates&gt; &lt;/ul&gt; &lt;/xsl:when&gt; &lt;xsl:when test="self::node()[@id=$id]"&gt; &lt;xsl:if test="./*"&gt; &lt;xsl:if test="./*[not(@id=$id)]"&gt; &lt;ul&gt; &lt;xsl:apply-templates select="siteMapNode"&gt; &lt;xsl:sort select="@month" data-type="number" order="descending"/&gt; &lt;/xsl:apply-templates&gt; &lt;/ul&gt; &lt;/xsl:if&gt; &lt;/xsl:if&gt; &lt;/xsl:when&gt; &lt;xsl:otherwise&gt; &lt;/xsl:otherwise&gt; &lt;/xsl:choose&gt; &lt;/li&gt; &lt;/xsl:template&gt; &lt;xsl:template match="siteMapNode/siteMapNode/siteMapNode/siteMapNode/siteMapNode"&gt; &lt;xsl:variable name="matchidandyearpartofquery" select="count(self::node()[@id=$id and @query_string=$query_string])" /&gt; &lt;li&gt; &lt;xsl:if test="$matchidandyearpartofquery &amp;gt; 0"&gt; &lt;xsl:attribute name="class"&gt; &lt;xsl:text&gt;active icon-nav-left&lt;/xsl:text&gt; &lt;/xsl:attribute&gt; &lt;/xsl:if&gt; &lt;a&gt; &lt;xsl:attribute name="href"&gt; &lt;xsl:value-of select="@url" /&gt; &lt;/xsl:attribute&gt; &lt;xsl:value-of select="@title" /&gt; &lt;/a&gt; &lt;/li&gt; &lt;/xsl:template&gt; &lt;/xsl:stylesheet&gt; </code></pre> <p>And some example XML input</p> <pre><code>&lt;siteMapNode id="id:144037" title="Home" url="index.jsp" depth="0" show_in_top="Yes" show_in_footer="No" use_as_default="No" query_string="" month="" year=""&gt; &lt;siteMapNode id="id:144037" title="Home" url="index.jsp" depth="1" show_in_top="Yes" show_in_footer="No" use_as_default="No" query_string="" month="" year="" /&gt; &lt;siteMapNode id="id:144513" title="Company" url="our-company/index.jsp" depth="1" show_in_top="Yes" show_in_footer="No" use_as_default="No" query_string="" month="" year=""&gt; &lt;siteMapNode id="id:144615" title="At a glance" url="our-company/at-a-glance.jsp" depth="2" show_in_top="No" show_in_footer="No" use_as_default="No" query_string="" month="" year="" /&gt; &lt;siteMapNode id="id:144005" title="Our Brands" url="our-company/our-brands.jsp" depth="2" show_in_top="No" show_in_footer="No" use_as_default="No" query_string="" month="" year="" /&gt; &lt;siteMapNode id="id:144629" title="Our Products" url="our-company/our-products.jsp" depth="2" show_in_top="No" show_in_footer="No" use_as_default="No" query_string="" month="" year="" /&gt; &lt;siteMapNode id="id:144638" title="Our Global Purpose" url="our-company/our-global-purpose.jsp" depth="2" show_in_top="No" show_in_footer="No" use_as_default="No" query_string="" month="" year="" /&gt; &lt;siteMapNode id="id:144002" title="Company History" url="our-company/company-history.jsp" depth="2" show_in_top="No" show_in_footer="No" use_as_default="No" query_string="" month="" year="" /&gt; &lt;siteMapNode id="id:144003" title="Leadership" url="our-company/leadership.jsp" depth="2" show_in_top="No" show_in_footer="No" use_as_default="No" query_string="" month="" year="" /&gt; &lt;/siteMapNode&gt; &lt;siteMapNode id="id:144016" title="News" url="news-press/newslisting.jsp" depth="1" show_in_top="Yes" show_in_footer="No" use_as_default="No" query_string="" month="" year=""&gt; &lt;siteMapNode id="id:144016" title="2012 Archive" url="news-press/newslisting.jsp?year=2012" depth="2" show_in_top="No" show_in_footer="No" use_as_default="No" query_string="year=2012" month="" year="2012"&gt; &lt;siteMapNode id="id:144016" title="December" url="news-press/newslisting.jsp?year=2012&amp;amp;month=12" depth="3" show_in_top="No" show_in_footer="No" use_as_default="No" query_string="year=2012&amp;amp;month=12" month="12" year="2012" /&gt; &lt;siteMapNode id="id:144016" title="April" url="news-press/newslisting.jsp?year=2012&amp;amp;month=4" depth="3" show_in_top="No" show_in_footer="No" use_as_default="No" query_string="year=2012&amp;amp;month=4" month="4" year="2012" /&gt; &lt;/siteMapNode&gt; &lt;siteMapNode id="id:144016" title="2013 Archive" url="news-press/newslisting.jsp" depth="2" show_in_top="No" show_in_footer="No" use_as_default="No" query_string="year=2013" month="" year=""/&gt; &lt;/siteMapNode&gt; &lt;/siteMapNode&gt; </code></pre> <p>And here is an example of the expected output HTML (here, the month december in the year 2012 has been selected from the news section)</p> <pre><code>&lt;li class="active"&gt;&lt;a href="news-press/newslisting.jsp?year=2012"&gt;2012 Archive&lt;/a&gt; &lt;ul&gt; &lt;li class="active icon-nav-left"&gt;&lt;a href="news-press/newslisting.jsp?year=2012&amp;amp;month=12"&gt;December&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="news-press/newslisting.jsp?year=2012&amp;amp;month=4"&gt;April&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt; &lt;/li&gt; &lt;li&gt;&lt;a href="news-press/newslisting.jsp"&gt;2013 Archive&lt;/a&gt;&lt;/li&gt; </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload