Use if statement to exclude all nodes of certain level and node type
Hi all,
I'm having some problems with a (relatively) complicated xslt statement.
I want to exclude a set of nodes from my navigation menu based on the following properties:
level = 4
name() != 'uBlogsyPost'
OR
name() != 'umbracoBlogPost'
so I want to exclude all items with a level of 4, with either the doctype of uBlogsyPost or umbracoBlogPost.
I would do it with a document property but I want it to be automatic as opposed to manual.
Here is my current xslt:
<xsl:if test="($node/umbracoNaviHide != '1') and (@level != 4 and (name() != 'uBlogsyPost' or name() != 'umbracoBlogPost'))">
This line is placed within a template that get's called in a loop that loops through every node in the site, then within the above if statement is code that outputs the menu itself.
With the above statement it stops as soon as it starts and does not output any code.
Could you perhaps post the whole XSLT snippet? I have an idea that what you're trying to do could be handled in a much better way using an apply-template actually. But would like to see more of the code.
As Jan implied, this sort of thing is actually better handled using match templates and the apply-templates instruction; One way of doing that looks like this:
From the above I understand that apply-templates tries to match a string or nodeset against all possible templates, either by properties, attributes or names.
The only question I have, is how does the below template call
Use if statement to exclude all nodes of certain level and node type
Hi all,
I'm having some problems with a (relatively) complicated xslt statement.
I want to exclude a set of nodes from my navigation menu based on the following properties:
so I want to exclude all items with a level of 4, with either the doctype of uBlogsyPost or umbracoBlogPost.
I would do it with a document property but I want it to be automatic as opposed to manual.
Here is my current xslt:
<xsl:if test="($node/umbracoNaviHide != '1') and (@level != 4 and (name() != 'uBlogsyPost' or name() != 'umbracoBlogPost'))">
This line is placed within a template that get's called in a loop that loops through every node in the site, then within the above if statement is code that outputs the menu itself.
With the above statement it stops as soon as it starts and does not output any code.
Thanks,
Max.
Hi Max
Could you perhaps post the whole XSLT snippet? I have an idea that what you're trying to do could be handled in a much better way using an apply-template actually. But would like to see more of the code.
/Jan
Sure, here is the xslt for the nav before I started messing around with it trying to achieve the above:
<?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:variable name="level" select="1"/>
<xsl:template match="/">
<div class="navtree">
<table cellspacing="0">
<tr>
<td id="navleft"></td>
<td id="navcentre">
<ul>
<li>
<!-- output home page node then run through template for all other top level nodes -->
<xsl:if test="$currentPage/@nodeName = 'Home'">
<xsl:attribute name="class">current</xsl:attribute>
</xsl:if>
<a href="/">Home</a></li></ul>
<xsl:call-template name="printListe">
<xsl:with-param name="node" select="$currentPage/ancestor-or-self::* [@isDoc and @level = 1]"/>
<xsl:with-param name="id" select="string('treemenu1')"/>
</xsl:call-template>
</td>
<td id="navright"></td>
</tr>
</table>
</div>
</xsl:template>
<xsl:template name="printListe">
<xsl:param name="node"/>
<xsl:param name="id"/>
<xsl:if test="($node/umbracoNaviHide != '1')">
<xsl:if test="count($node/* [@isDoc and umbracoNaviHide != 1]) > 0">
<ul>
<xsl:if test="$id != ''">
<xsl:attribute name="id"><xsl:value-of select="$id"/></xsl:attribute>
</xsl:if>
<xsl:for-each select="$node/* [@isDoc and umbracoNaviHide != 1]">
<xsl:call-template name="buildLi">
<xsl:with-param name="node" select="." />
<xsl:with-param name="href" select="umbraco.library:NiceUrl(@id)" />
<xsl:with-param name="text" select="@nodeName" />
</xsl:call-template>
</xsl:for-each>
</ul>
</xsl:if>
</xsl:if>
</xsl:template>
<!-- nav list item builder template, used above -->
<xsl:template name="buildLi">
<xsl:param name="node" />
<xsl:param name="href" />
<xsl:param name="text" />
<li>
<a>
<xsl:attribute name="href">
<xsl:value-of select="$href" />
</xsl:attribute>
<xsl:if test="string-length($text) > 25">
<xsl:attribute name="title">
<xsl:value-of select="$text" />
</xsl:attribute>
</xsl:if>
<!-- if text needs shrinking, add full length version in title -->
<xsl:choose>
<xsl:when test="string-length(@nodeName) > 25">
<xsl:value-of select="concat((substring($text,0,24)),'...')" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text" />
</xsl:otherwise>
</xsl:choose>
</a>
<!-- shrink text if need be -->
<xsl:if test="count($node/*[@isDoc and umbracoNaviHide != 1]) > 0">
<xsl:call-template name="printListe">
<xsl:with-param name="node" select="."/>
</xsl:call-template>
</xsl:if>
</li>
</xsl:template>
</xsl:stylesheet>
Hi Max,
As Jan implied, this sort of thing is actually better handled using match templates and the apply-templates instruction; One way of doing that looks like this:
/Chriztian
Great! That did it. Only problem was that the <ul> tags were still being rendered inside the
template which, in ie6 (surprise surprise) messed up the menu. I changed the code slightly to this:
<?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:umb="urn:umbraco.library"
exclude-result-prefixes="umb"
>
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
<xsl:param name="currentPage" />
<xsl:variable name="level" select="1" />
<xsl:variable name="navRoot" select="$currentPage/ancestor-or-self::*[@level = $level][not(umbracoNaviHide = 1)]" />
<xsl:variable name="navRootItems" select="$navRoot/*[@isDoc][not(umbracoNaviHide = 1)]" />
<xsl:template match="/">
<div class="navtree">
<table cellspacing="0">
<tr>
<td id="navleft" />
<td id="navcentre">
<ul>
<li>
<xsl:if test="$currentPage/@nodeName = 'Home'"><xsl:attribute name="class">current</xsl:attribute></xsl:if>
<a href="/">Home</a>
</li>
</ul>
<xsl:if test="$navRootItems">
<ul id="treemenu1">
<xsl:apply-templates select="$navRootItems" />
</ul>
</xsl:if>
</td>
<td id="navright" />
</tr>
</table>
</div>
</xsl:template>
<xsl:template match="*[@isDoc]">
<li>
<xsl:if test="@id = $currentPage/@id"><xsl:attribute name="class">current</xsl:attribute></xsl:if>
<a href="{umb:NiceUrl(@id)}">
<xsl:apply-templates select="@nodeName" />
</a>
<xsl:if test="*[@isDoc][not(umbracoNaviHide = 1)][not((self::uBlogsyFolderMonth | self::umbracoBlogDateFolder)[@level = 5])]">
<ul>
<xsl:apply-templates select="*[@isDoc][not(umbracoNaviHide = 1)][not((self::uBlogsyFolderMonth | self::umbracoBlogDateFolder)[@level = 5])]" />
</ul>
</xsl:if>
</li>
</xsl:template>
<xsl:template match="@nodeName[string-length() > 25]">
<xsl:attribute name="title">
<xsl:value-of select="." />
</xsl:attribute>
<xsl:value-of select="concat(substring(., 1, 24), '…')" />
</xsl:template>
</xsl:stylesheet>
Which seems to have fixed it.
From the above I understand that apply-templates tries to match a string or nodeset against all possible templates, either by properties, attributes or names.
The only question I have, is how does the below template call
<xsl:template match="@nodeName[string-length() > 25]">
Know to simply render the non-truncated version of @nodeName if it is less than 25 characters long?
Thanks for your help, I have learnt a lot!!
Max.
is working on a reply...