Getting all nodes at parent level if no child in XSLT
Hi,
I have a XSLT macro with code snippet as below.
... <xsl:template match="/"> <xsl:for-each select="$currentPage/child::* [@isDoc and string(umbracoNaviHide) != '1']"> <li> <a href="{umbraco.library:NiceUrl(@id)}"> <xsl:value-of select="@nodeName"/> </a> </li> </xsl:for-each> </xsl:template> ...
I am using this to display Left side navigation . The problem I am having is when my content tree has no child, it displays nothing on the left side. What I want is that if there is no child, I want to display all nodes above that level.
I have tried couple of things but no luck. Any help will be appreciated.
It's not that clear what you mean by 'all nodes above that level', but anyway it looks like you need to use conditional elements of Xslt, for instance:
Conditionals like that also defeat some subtle problem that your original code has - in case when there're no child nodes it would render an empty <ul></ul> tag that's not valid html.
Thanks a lot. Conditional elements under template match is what I was looking for. I have got 90% working so far. Only left with one logical thing. This is what I have got and it's working fine. This is the part I am unable to get it working: I want all the nodes at parent level of a child to be displayed WHEN the child has no further node (this is the last branch in the tree). I need the value of level to be a variable somehow. So if child is at 3rd level, the value of level should be 3. If child is at 4th level, the value should be 4. I am not sure how can I get this value of level in first condition or somewhere else in code ?
This uses a separate template for the links and then selects the currentPage's children only if it has any, otherwise it goes up two levels and selects the children of that one (I would have thought you'd want the siblings of $currentPage if it has no children? If that's what you actually want, just remove one set of "../" from the expression):
Sure thing - so first of all: In XSLT you work with nodesets 95% of the time. Even though you say select="$currentPage", you're creating a nodeset that contains a single node.
You can filter a set by supplying a "predicate" - an expression inside square brackest, e.g.: $currentPage[color = '#ff8000'] - only select $currentPage if its "color" property has the value '#ff8000'. (A bit like WHERE or HAVING...)
In your case, you want to use the parents only if the currentpage has no (visible) children - so I added the predicate [not(*[@isDoc][not(umbracoNaviHide = 1)])] - and it looks complicated, but if you break it down it's not that bad:
[ # start outer filter
not( # negate the embedded expression
*[@isDoc] # select child elements with an isDoc attribute
[not(umbracoNaviHide = 1)] # select those that doesn't have the "hide" box checked
)] # end outer filter
So if the innermost nodeset is empty (no visible child documents),
the not() function will return true() and the rest of the expression
will be used.
Getting all nodes at parent level if no child in XSLT
Hi,
I have a XSLT macro with code snippet as below.
...
<xsl:template match="/">
<xsl:for-each select="$currentPage/child::* [@isDoc and string(umbracoNaviHide) != '1']">
<li>
<a href="{umbraco.library:NiceUrl(@id)}">
<xsl:value-of select="@nodeName"/>
</a>
</li>
</xsl:for-each>
</xsl:template>
...
I am using this to display Left side navigation . The problem I am having is when my content tree has no child, it displays nothing on the left side. What I want is that if there is no child, I want to display all nodes above that level.
I have tried couple of things but no luck. Any help will be appreciated.
Thanks
Dinesh
It's not that clear what you mean by 'all nodes above that level', but anyway it looks like you need to use conditional elements of Xslt, for instance:
Conditionals like that also defeat some subtle problem that your original code has - in case when there're no child nodes it would render an empty <ul></ul> tag that's not valid html.
Thanks a lot. Conditional elements under template match is what I was looking for. I have got 90% working so far. Only left with one logical thing. This is what I have got and it's working fine. This is the part I am unable to get it working: I want all the nodes at parent level of a child to be displayed WHEN the child has no further node (this is the last branch in the tree). I need the value of level to be a variable somehow. So if child is at 3rd level, the value of level should be 3. If child is at 4th level, the value should be 4. I am not sure how can I get this value of level in first condition or somewhere else in code ?
<xsl:param name="currentPage"/>
<xsl:variable name="level" select="3"/>
<xsl:variable name="currentChildren"
select="$currentPage/child::*[@isDoc and string(umbracoNaviHide) != '1']"/>
<xsl:variable name="currentParents"
select="$currentPage/ancestor-or-self::* [@level=$level]/* [@isDoc and string(umbracoNaviHide) != '1']"/>
<xsl:template match="/">
<xsl:for-each select="$currentChildren">
<xsl:sort select="sortSequence" data-type="number" order="ascending"/>
<div class="subNavLink">
<a href="{umbraco.library:NiceUrl(@id)}">
<xsl:value-of select="@nodeName"/>
</a>
</div>
</xsl:for-each>
<xsl:if test="count($currentChildren) = 0">
<div class="subNavLink">
<xsl:for-each select="$currentParents">
<xsl:sort select="sortSequence" data-type="number" order="ascending"/>
<div class="subNavLink">
<a href="{umbraco.library:NiceUrl(@id)}">
<xsl:value-of select="@nodeName"/>
</a>
</div>
</xsl:for-each>
</div>
</xsl:if>
</xsl:template>
Look at it - probably it will work:
This should select all elements that are on the level that's one step above $currentPage.
Hi Dinesh,
This uses a separate template for the links and then selects the currentPage's children only if it has any, otherwise it goes up two levels and selects the children of that one (I would have thought you'd want the siblings of $currentPage if it has no children? If that's what you actually want, just remove one set of "../" from the expression):
/Chriztian
AWESOME! Thanks a lot. I need to remove one set of ../
I am not much proficient in XSLT. Can you please explain me the meaning of putting not in front of currentParents XSLT ?
$currentPage[not(*[@isDoc][not(umbracoNaviHide = 1)])]
Hi Dinesh,
Sure thing - so first of all: In XSLT you work with nodesets 95% of the time. Even though you say select="$currentPage", you're creating a nodeset that contains a single node.
You can filter a set by supplying a "predicate" - an expression inside square brackest, e.g.: $currentPage[color = '#ff8000'] - only select $currentPage if its "color" property has the value '#ff8000'. (A bit like WHERE or HAVING...)
In your case, you want to use the parents only if the currentpage has no (visible) children - so I added the predicate [not(*[@isDoc][not(umbracoNaviHide = 1)])] - and it looks complicated, but if you break it down it's not that bad:
Hope that makes sense :-)
/Chriztian
Hi Chriztian,
Thanks a lot for spending time on my problem and further clarifying my XSLT doubts.
I really appreciate it.
Regards
Dinesh
is working on a reply...