disable the current link in a breadcrumb trail - xslt

Does anyone know how to disable the current link in a breadcrumb trail.
I am working on a bspoke CMS and i have been asked to remove the current link in the breadcrumb trail.
All that i know in XSLT has failed and i have quite some time on, XSLT is no my strength and i need some helpful input.
Please help
here is the XSLT code:
[code]
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" omit-xml-declaration="yes" />
<!--
Variable to determine if the current open page is displayed as a link or plain text
select = 1 - displays plain text link
select = 0 - displays link (default value)
-->
<xsl:variable name="DisableCurrentPageLink" select="0" />
<xsl:template match="BreadCrumbTrail">
<xsl:apply-templates select="Page" />
</xsl:template>
<xsl:template match="Page">
<span class="BCTDelimiter">»</span>
<xsl:choose>
<xsl:when test="$DisableCurrentPageLink = 1">
<xsl:choose>
<xsl:when test="#IsOpenPage = 1">
<span class="breadcrumb-link">
<xsl:value-of select="#Title"/>
</span>
</xsl:when>
<xsl:otherwise>
<a href="{#URL}" class="breadcrumb-link" title="{#Title}">
<xsl:value-of select="#Title" />
</a>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<a href="{#URL}" class="breadcrumb-link" title="{#Title}">
<xsl:value-of select="#Title" />
</a>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
[/code]

It's hard without seeing the input form. That code will make an unlinked span for pages that have <page IsOpenPage="1"> as the markup, but does you CMS add that attribute for the relevant pages?
If the currently open page is always last in the trail you could change
<xsl:when test="#IsOpenPage = 1">
to
<xsl:when test="not(following-sibling::Page)">

Related

XSLT 1.0 How to match a string to another, list it, and under a different heading, list the unmatched string (specific situation)

I have been training myself in XSLT for about 1.5 months. I have made a simplified shorter version of what I am having trouble figuring out, and would highly appreciate any help at all as I am stuck on the issue. Thanks!
Basic Situation:
There's a string in a root attribute with an ancestor of element definition
xpath:
/v3:QualityMeasureDocument/v3:component/v3:dataCriteriaSection/v3:definition/v3:valueSet/v3:id/#root
...that when matched with the id from a valueSet attribute with an ancestor of element entry, xpath:
/v3:QualityMeasureDocument/v3:component/v3:dataCriteriaSection/v3:entry/v3:observationCriteria/v3:value/#valueSet
or
/v3:QualityMeasureDocument/v3:component/v3:dataCriteriaSection/v3:entry/v3:observationCriteria/v3:code/#valueSet
the output (needs to and currently does) display the string, along with its required attribute(s).
However, when there is no match for the string in these locations, the string must also be listed, with a 'Not Specified' header.
THE ERROR:
The 'Not Specified' header and its string are being listed even when all of the existing strings match. In this scenario, there should only be matched strings listed.
The Problem Translator (XSL file) :
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xalan="http://xml.apache.org/xalan"
xmlns:v3="urn:hl7-org:v3"
xmlns:rvs="urn:ihe:iti:svs:2008">
<xsl:output method="html" standalone="yes" omit-xml-declaration="no" indent="yes" xalan:indent-amount="2"/>
<xsl:template
match="/v3:QualityMeasureDocument">
<html>
<head>
<title>Test 'I'</title>
</head>
<body>
<ul>
<xsl:apply-templates select="//v3:dataCriteriaSection" />
</ul>
</body>
</html>
</xsl:template>
<xsl:template
match="v3:dataCriteriaSection">
<xsl:for-each select="//v3:entry">
<xsl:if test="*/v3:value/#valueSet">
<xsl:call-template name="definitionValueSet">
<xsl:with-param name="cur_valueSetID" select="*/v3:value/#valueSet"/>
</xsl:call-template>
</xsl:if>
<xsl:if test="*/v3:code/#valueSet">
<xsl:call-template name="definitionValueSet">
<xsl:with-param name="cur_valueSetID" select="*/v3:code/#valueSet"/>
</xsl:call-template>
</xsl:if>
<xsl:if test="*/v3:participant/v3:roleParticipant/v3:code/#valueSet">
<xsl:call-template name="definitionValueSet">
<xsl:with-param name="cur_valueSetID" select="*/v3:participant/v3:roleParticipant/v3:code/#valueSet"/>
</xsl:call-template>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template
name="definitionValueSet">
<xsl:param name="cur_valueSetID"/>
<xsl:for-each select="//v3:valueSet">
<xsl:choose>
<xsl:when test="$cur_valueSetID != v3:id/#root or
not( v3:text/v3:reference[starts-with(#value, 'https://') and contains(#value, $cur_valueSetID)] ) or
not( v3:text/rvs:RetrieveValueSetResponse/rvs:ValueSet/#id = $cur_valueSetID )">
<xsl:if test="not($cur_valueSetID = '')">
<li>
<xsl:text>Not Specified</xsl:text>
<ul>
<li>
<xsl:text>ValueSet: </xsl:text>
<xsl:value-of select="$cur_valueSetID"></xsl:value-of>
</li>
</ul>
</li>
</xsl:if>
</xsl:when>
<xsl:when test="v3:id/#root = $cur_valueSetID">
<xsl:if test="v3:text/v3:reference[starts-with(#value, 'https://') and contains(#value, $cur_valueSetID)]">
<xsl:if test="v3:text/rvs:RetrieveValueSetResponse/rvs:ValueSet/#id = $cur_valueSetID">
<li>
<xsl:text>Id: </xsl:text>
<xsl:value-of select="v3:id/#root"/>
<xsl:for-each select="v3:text/rvs:RetrieveValueSetResponse/rvs:ValueSet/rvs:ConceptList/rvs:Concept">
<ul>
<li>
<xsl:if test="not(#code = '')">
<xsl:if test="#code">
<xsl:text>code = </xsl:text>
<xsl:value-of select="#code"></xsl:value-of>
<xsl:text> </xsl:text>
</xsl:if>
</xsl:if>
</li>
</ul>
</xsl:for-each>
</li>
</xsl:if>
</xsl:if>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
XML input file 'I' xml :
<?xml version="1.0" encoding="UTF-8"?>
<QualityMeasureDocument xmlns="urn:hl7-org:v3">
<component>
<dataCriteriaSection>
<definition>
<valueSet>
<!-- Value Set for Race -->
<id root='1.1.1.1.1.1.1' />
<text>
<reference
value='https://localhost/RetrieveValueSet?id=1.1.1.1.1.1.1' />
<RetrieveValueSetResponse xmlns="urn:ihe:iti:svs:2008">
<ValueSet id="1.1.1.1.1.1.1">
<ConceptList>
<Concept code="4" />
<Concept code="5" />
<Concept code="6" />
</ConceptList>
</ValueSet>
</RetrieveValueSetResponse>
</text>
</valueSet>
</definition>
<definition>
<valueSet>
<id root='1.1.1.1.1.1.2' />
<text>
<reference
value='https://localhost/RetrieveValueSet?id=1.1.1.1.1.1.2' />
<RetrieveValueSetResponse xmlns="urn:ihe:iti:svs:2008">
<ValueSet id="1.1.1.1.1.1.2">
<ConceptList>
<Concept code="007.2" />
<Concept code="007.3" />
</ConceptList>
</ValueSet>
</RetrieveValueSetResponse>
</text>
</valueSet>
</definition>
<entry>
<observationCriteria>
<code code="424144002" codeSystem="123123213"
displayName="FEWFW" />
<value>
<low />
<high />
</value>
</observationCriteria>
</entry>
<entry>
<observationCriteria>
<code code="DFHKJ" codeSystem="ASKJDHK" displayName="ASDNJK" />
<value>
<width />
</value>
</observationCriteria>
</entry>
<entry>
<observationCriteria>
<code code="FDSFD" codeSystem="JHBHJB" displayName="HJGJH" />
<value valueSet="1.1.1.1.1.1.1" />
</observationCriteria>
</entry>
<entry>
<encounterCriteria>
<code valueSet="1.1.1.1.1.1.2" />
</encounterCriteria>
</entry>
</dataCriteriaSection>
</component>
</QualityMeasureDocument>
Expected Output Code 'I' HTML :
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<html xmlns:xalan="http://xml.apache.org/xalan" xmlns:rvs="urn:ihe:iti:svs:2008" xmlns:v3="urn:hl7-org:v3">
<head>
<title>Test 'I'</title>
</head>
<body>
<ul>
<li>Id: 1.1.1.1.1.1.1
<ul>
<li>code = 4 </li>
</ul>
<ul>
<li>code = 5 </li>
</ul>
<ul>
<li>code = 6 </li>
</ul>
</li>
<li>Id: 1.1.1.1.1.1.2
<ul>
<li>code = 007.2 </li>
</ul>
<ul>
<li>code = 007.3 </li>
</ul>
</li>
</ul>
</body>
</html>
It would be simple to create the correct output through a hack, or just erasing code, but this needs to work in all situations. Such as, having no matches at all and displaying only the 'Not Specified' header and its string each time it occurs, or a mixture of both situations. The code currently works in a situation where there are no matches, and displays the 'Not Specified' header and its string each time it occurs.
It seems like if this could be done, "if it's not a match AND hasn't already been listed" it would solve the problem.
Hope that helps. If you would like more information or more files let me know. Any tips at all would be great! Thanks.
I think the main problem you are having is within your named template "definitionValueSet", where you loop over valueSet elements with an xsl:for-each
<xsl:for-each select="//v3:valueSet">
Within this you test whether the relevant attributes match your current parameter, and if you find a match, you output your list. But all valueSet elements will be searched, so even if one matches, you are still going to be processing the ones that don't and so your xsl:if for a non-match is called too. This results in the "Not Specified" being output.
What you really need to be doing is matching only the valueSet element if it exists, and if none exist that match, output your "Not Specified".
One way to do this is to first create a variable that holds the unique id of the valueSet element that matches
<xsl:variable name="valueSet">
<xsl:value-of select="generate-id(//v3:valueSet[v3:id/#root = $cur_valueSetID and v3:text/v3:reference[starts-with(#value, 'https://') and contains(#value, $cur_valueSetID)] and v3:text/rvs:RetrieveValueSetResponse/rvs:ValueSet/#id = $cur_valueSetID])"/>
</xsl:variable>
Then, you can test whether this has been set, and if so, apply the template for that element. If not set, you can have your not-specified code
<xsl:choose>
<xsl:when test="$valueSet">
<xsl:apply-templates select="//v3:valueSet[generate-id() = $valueSet]"/>
</xsl:when>
<xsl:otherwise>
<!-- Not Specified -->
</xsl:otherwise>
</xsl:choose>
Here is the full XSLT, which should hopefully give the output you require
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xalan="http://xml.apache.org/xalan" xmlns:v3="urn:hl7-org:v3" xmlns:rvs="urn:ihe:iti:svs:2008">
<xsl:output method="html" standalone="yes" omit-xml-declaration="no" indent="yes" xalan:indent-amount="2"/>
<xsl:template match="/v3:QualityMeasureDocument">
<html>
<head>
<title>Test 'I'</title>
</head>
<body>
<ul>
<xsl:apply-templates select="//v3:dataCriteriaSection"/>
</ul>
</body>
</html>
</xsl:template>
<xsl:template match="v3:dataCriteriaSection">
<xsl:for-each select=".//v3:entry">
<xsl:if test="*/v3:value/#valueSet">
<xsl:call-template name="definitionValueSet">
<xsl:with-param name="cur_valueSetID" select="*/v3:value/#valueSet"/>
</xsl:call-template>
</xsl:if>
<xsl:if test="*/v3:code/#valueSet">
<xsl:call-template name="definitionValueSet">
<xsl:with-param name="cur_valueSetID" select="*/v3:code/#valueSet"/>
</xsl:call-template>
</xsl:if>
<xsl:if test="*/v3:participant/v3:roleParticipant/v3:code/#valueSet">
<xsl:call-template name="definitionValueSet">
<xsl:with-param name="cur_valueSetID" select="*/v3:participant/v3:roleParticipant/v3:code/#valueSet"/>
</xsl:call-template>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template name="definitionValueSet">
<xsl:param name="cur_valueSetID"/>
<xsl:variable name="valueSet">
<xsl:value-of select="generate-id(//v3:valueSet[v3:id/#root = $cur_valueSetID and v3:text/v3:reference[starts-with(#value, 'https://') and contains(#value, $cur_valueSetID)] and v3:text/rvs:RetrieveValueSetResponse/rvs:ValueSet/#id = $cur_valueSetID])"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="$valueSet != ''">
<xsl:apply-templates select="//v3:valueSet[generate-id() = $valueSet]"/>
</xsl:when>
<xsl:otherwise>
<li>
<xsl:text>Not Specified</xsl:text>
<ul>
<li>
<xsl:text>ValueSet: </xsl:text>
<xsl:value-of select="$cur_valueSetID"/>
</li>
</ul>
</li>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="v3:valueSet">
<li>
<xsl:text>Id: </xsl:text>
<xsl:value-of select="v3:id/#root"/>
<xsl:for-each select="v3:text/rvs:RetrieveValueSetResponse/rvs:ValueSet/rvs:ConceptList/rvs:Concept">
<ul>
<li>
<xsl:if test="not(#code = '')">
<xsl:if test="#code">
<xsl:text>code = </xsl:text>
<xsl:value-of select="#code"/>
<xsl:text/>
</xsl:if>
</xsl:if>
</li>
</ul>
</xsl:for-each>
</li>
</xsl:template>
</xsl:stylesheet>
Do note, as mentioned in a comment, be careful with the use of expression //v3:entry. This is an absolute expression, and will match any element at all in the document (i.e it searches from the root element downwards). If you wanted only to look under the current element, use the relative expression .//v3:entry
EDIT: For a slight variant on this, as a potentially more efficient way to look up the valueSet elements you could define a key at the top of the XSLT document
<xsl:key name="valueSet" match="v3:valueSet" use="generate-id()" />
Then, instead of doing this to look up the correct valueSet element
<xsl:apply-templates select="//v3:valueSet[generate-id() = $valueSet]"/>
You could use the key instead
<xsl:apply-templates select="key('valueSet', $valueSet)"/>
The following is a simple-ish alternate solution (does not use generate-id() or key() ) provided for comprehension. It is likely less efficient than and should not replace Tim C's excellent answer. I am simply providing this so people can learn, and to show that I put full effort into solving this issue, instead of just getting what I needed and moving on.
The solution is a fix to the original 'Problem Translator'. The only section that needs to be edited (although heavily) from that XSL file is the "definitionValueSet" named template.
First we need to create a variable $valueSetData which stores all of the values of v3:id/#root in a one time pass, with a ',' in between them, in order to be individually referenced later. It's like a new temporary database.
The for-each contains a predicate which limits the matches as per requirements. These are included within the declaration because they are local nodes there. Also, this keeps from processing extra conditional checks later.
<xsl:variable name="valueSetData">
<xsl:for-each select="//v3:valueSet[
v3:text/v3:reference[starts-with(#value, 'https://') and contains(#value, $cur_valueSetID)] and
v3:text/rvs:RetrieveValueSetResponse/rvs:ValueSet/#id = $cur_valueSetID]">
<xsl:value-of select="v3:id/#root"/>
<xsl:text>,</xsl:text>
</xsl:for-each>
</xsl:variable>
Next we have the choose statement, edited for specifics. The statement determines if there is a match to the $cur_valueSetID within the $valueSetData 'database'.
The for-each predicate limits duplicate matches (with the wrong values in addition due to context).
<xsl:choose>
<xsl:when test="contains($valueSetData, $cur_valueSetID)">
<xsl:for-each select="//v3:valueSet[$cur_valueSetID = v3:id/#root]">
<!-- Display found matches which meet all requirements -->
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<!-- Display Not Specified -->
</xsl:otherwise>
</xsl:choose>
The full "definitionValueSet" template:
<xsl:template
name="definitionValueSet">
<xsl:param name="cur_valueSetID"/>
<xsl:variable name="valueSetData">
<xsl:for-each select="//v3:valueSet[
v3:text/v3:reference[starts-with(#value, 'https://') and contains(#value, $cur_valueSetID)] and
v3:text/rvs:RetrieveValueSetResponse/rvs:ValueSet/#id = $cur_valueSetID]">
<xsl:value-of select="v3:id/#root"/>
<xsl:text>,</xsl:text>
</xsl:for-each>
</xsl:variable>
<xsl:choose>
<xsl:when test="contains($valueSetData, $cur_valueSetID)">
<xsl:for-each select="//v3:valueSet[$cur_valueSetID = v3:id/#root]">
<li>
<xsl:text>Id: </xsl:text>
<xsl:value-of select="v3:id/#root"/>
<xsl:for-each select="v3:text/rvs:RetrieveValueSetResponse/rvs:ValueSet/rvs:ConceptList/rvs:Concept">
<ul>
<li>
<xsl:if test="not(#code = '')">
<xsl:if test="#code">
<xsl:text>code = </xsl:text>
<xsl:value-of select="#code"></xsl:value-of>
<xsl:text/>
</xsl:if>
</xsl:if>
</li>
</ul>
</xsl:for-each>
</li>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<li>
<xsl:text>Not Specified</xsl:text>
<ul>
<li>
<xsl:text>ValueSet: </xsl:text>
<xsl:value-of select="$cur_valueSetID"></xsl:value-of>
</li>
</ul>
</li>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

XSL counter on specific condition for SharePoint 2010 CQWP

This is the first time I have ever posted a question so apologese in advance if I jibber here.
I am trying to put together a CQWP with jQuery tabs slider functionality. The HTML I want to output should be in the form of 2 UL's. The first with li anchor tags with #associated-ul-id
The second ul's should have ids that associate with the list items in the first. Eg
<div id="tabs" class="news">
<div class="news-pagination">
« Prev
<ul id="carouseltext" class="horizontal-text order">
<li>System</li>
<li>School</li>
</ul>
» Next
<div class="clear"> </div>
</div>
<ul id="tabs-1" class="feed order">
<li>title 1</li>
<li>title 2</li>
</ul>
<ul id="tabs-2" class="feed order">
<li>title 3</li>
</ul>
</div>
The original XML starts off in the form
My XSL goes through the XML twice to fill the 2 ul's. The first time it just adds a new list item when the __begincolumn and __begingroup variables are true. I striped down the functionality here to just output the header. Here's a stripped down version of the XSL
<xsl:template match="/">
<xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row" />
<xsl:variable name="RowCount" select="count($Rows)" />
<xsl:variable name="FirstRow" select="1" />
<xsl:param name="ColNumber" select="1" />
<xsl:for-each select="$Rows" >
<xsl:variable name="CurPosition" select="position()" />
<xsl:variable name="BeginNewsItemsList1" select="string('<ul id="tabs-')" />
<xsl:variable name="BeginNewsItemsList2" select="string('"class="feed order">')" />
<xsl:variable name="BeginNewsItemsList" select="concat($BeginNewsItemsList1, $ColNumber, $BeginNewsItemsList2)" />
<xsl:if test="($CurPosition >= $FirstRow and $CurPosition <= $LastRow)">
<xsl:variable name="StartNewGroup" select="#__begingroup = 'True'" />
<xsl:variable name="StartNewColumn" select="#__begincolumn = 'True'" />
<xsl:when test="$StartNewGroup and $StartNewColumn">
<xsl:choose>
<xsl:when test="$CurPosition = $FirstRow">
<xsl:value-of disable-output-escaping="yes" select="$BeginNewsItemsList" />
</xsl:when>
<xsl:otherwise>
<!-- other instructions -->
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$StartNewGroup">
<xsl:call-template name="OuterTemplate.CallFooterTemplate"/>
<xsl:value-of disable-output-escaping="yes" select="concat($EndColumn, $BeginNewsItemsList)" />
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template name="OuterTemplate.Count">
<xsl:param name="ColNumber" />
<xsl:value-of select="$ColNumber + 1" />
</xsl:template>
For the second for-each loop I'm having trouble setting up a counter so that I can add the number to the end of the id for each new list id="tabs-1", id="tabs-2", etc.
In theory I think I should set a parameter outside my for-each loop and then in the loop call a template that gets the parameter value and increments it. That would mean it would increment only when the template is called.
I can't use position() for this as it doesn't correspond to the values I want. I've tried to follow a couple a few blogs about recursive programming with xsl, but I can't seem to find anything that works. I'm sure I'm just writing the XSL wrong, but I'm having a bit of a brain dump now.
If anybody could point me in the right direction that would be awesome. Thanks very much.
You can't change variable's values after declaration. You can use them in expressions and/or pass as parameters. Thus, you can't use outside variable as counter explicitly. One available trick is recursive cycle like:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="root">
<HTML>
<BODY>
<xsl:call-template name="for">
<xsl:with-param name="i" select="1"/>
<xsl:with-param name="n" select="5"/>
</xsl:call-template>
</BODY>
</HTML>
</xsl:template>
<xsl:template name="for">
<xsl:param name="i"/>
<xsl:param name="n"/>
<xsl:value-of select="$i"/>
<xsl:if test="$i < $n">
<xsl:text>, </xsl:text>
<xsl:call-template name="for">
<xsl:with-param name="i" select="$i+1"/>
<xsl:with-param name="n" select="$n"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
result:
1, 2, 3, 4, 5

XSL Sorting With Sitecore

I'm not very familiar with xsl, so I'm sort of stumbling my way though this.
My xsl file is building a menu. I am trying to sort the menu items by the value in menu title field in Sitecore. When I run the code, it does not sort. It just writes out each menu item four times.
Can anyone shed some light on what I am missing?
<xsl:template name="show-title">
<xsl:param name="root" />
<xsl:for-each select="$sc_currentitem/item">
<xsl:sort select="sc:fld('menu title',.)" order="ascending"/>
<xsl:choose>
<xsl:when test="sc:fld('menu title',$root)!=''">
<sc:text field="menu title" select="$root" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$root/#name" />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
EDIT: Below is the data that the code above is generating
Example Output:
03/05/201203/05/201203/05/201203/05/2012
03/01/201203/01/201203/01/201203/01/2012
03/08/201203/08/201203/08/201203/08/2012
03/02/201203/02/201203/02/201203/02/2012
03/07/201203/07/201203/07/201203/07/2012
I am trying to get it to generate the following:
03/01/2012
03/02/2012
03/05/2012
03/07/2012
03/08/2012
Thanks!
It looks like you are trying to read menu title field from the wrong node. You should be reading it from context node --> . <--
Try this
<xsl:template name="show-title">
<xsl:param name="root" />
<xsl:for-each select="$sc_currentitem/item">
<xsl:sort select="sc:fld('menu title',.)" order="ascending"/>
<xsl:choose>
<xsl:when test="sc:fld('menu title',$root)!=''">
<sc:text field="menu title" select="." />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="./#name" />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
This is just a guess as you don't really supply enough information for anyone to do more than guess but....
Within your for-each you are referring to $root e.g. <xsl:value-of select="$root/#name" />
I am guessing that the $root parameter contains a list of some kind and that you should be selecting just part of this list based on some value from the current for-each context

XSLT xsl:apply-templates Conditional Syntax

I've got the following XSLT code which lists out the folders and their file items from a specified node.
This all works fine but I'd like to parameterise the page and optionally filter its output by a tag value.
Being an XLST numpty I'm stumped with the syntax for the conditional I should be putting in under the <xsl:when test="$tag"> clause - can someone please help ?
<xsl:variable name="tag" select="umbraco.library:Request('tag')" />
<xsl:template match="/">
<!-- Root folder in Media that holds the folders to output -->
<xsl:variable name="mediaRootFolderId" select="5948" />
<!-- Pass in true() to get XML for all nodes below -->
<xsl:variable name="mediaRootNode" select="umbraco.library:GetMedia($mediaRootFolderId, true())" />
<xsl:choose>
<xsl:when test="$tag">
</xsl:when>
<xsl:otherwise>
<!-- If we didn't get an error, output Folder elements that contain Image elements -->
<xsl:apply-templates select="$mediaRootNode[not(error)]/Folder[File]" >
<xsl:sort select="#nodeName"/>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Template for folders -->
<xsl:template match="Folder">
<div class="folder">
<h2>Folder: <xsl:value-of select="#nodeName" /></h2>
<div class="images">
<xsl:apply-templates select="File">
<xsl:sort select="#nodeName"/>
</xsl:apply-templates>
</div>
</div>
</xsl:template>
<!-- Template for files -->
<xsl:template match="File">
File: <a href="{umbracoFile}" alt="{#nodeName}" ><xsl:value-of select="#nodeName" /></a> <br/>
</xsl:template>
Instead of the long <xsl:choose> instruction, use:
<xsl:apply-templates select=
"$mediaRootNode[not($tag)][not(error)]
/Folder[File]" >
Explanation: For the XPath expression in the select attribute above to select a non-empty set of nodes it is necessary that boolean($tag) is true(). Thus the above single <xsl:apply-templates> instruction is equivalent to the long <xsl:choose> in the question.
you can test if $tag is set like this.
<xsl:param name="tag">
<xsl:message terminate="yes">
$tag has not been set
</xsl:message>
</xsl:param>
This isn't standard though, it'll work on most XSLT processors though.
If you wanted to be absolutely save, you could set the value to an illegal value (such as 1 div 0) and test for it in the body of the template:
<xsl:param name="tag" select="1 div 0" />
<xsl:if test="$tag = 1 div 0">
<xsl:message terminate="yes">
$tag has not been set, or has been set to Infinity, which is invalid.
</xsl:message>
</xsl:if>
Source: O'Reilly XSLT Cookbook

Display different xsl:attribute depending on the ending of a string

I have the following xsl code in an xsl document
<A target="_blank" style="text-decoration=none">
<xsl:attribute name="href">viewdoc.aspx?doc=<xsl:value-of select="URLFilePath"/>&mode=inline</xsl:attribute>
<xsl:attribute name="prefix"><xsl:value-of select="FileName"/>: </xsl:attribute>
<IMG src="images/word_small.gif" border="0"/>
</A>
and in the code-behind I am doing this
newItemNode = xmlDocument.CreateElement("URLFilePath")
newItemNode.InnerText = correctedPath
xmlItemNode.ParentNode.AppendChild(newItemNode)
Now that works fine for word documents. However I need a way in code to check the extension of the file, and display the correct Image and xsl:attribute depending on the If statement.
So the If statement will be like this:-
If correctedPath.ToLower.Contains(".doc") Then
//display the word icon and attributes
Else
//display the excel icon and attributes
End If
Can you please give me some tips and help on how I can achieve this?
Thanks
Just using contains() may generally produce the wrong results (see the test XML document).
What is necessary is a ends-with() function, which is standard in XPath 2.0 and can be implemented in XSLT 1.0 as in the following transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="URLFilePath">
<xsl:variable name="visDoc">
<xsl:call-template name="ends-with">
<xsl:with-param name="pEnding" select="'.doc'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="visXls">
<xsl:call-template name="ends-with">
<xsl:with-param name="pEnding" select="'.xls'"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$visDoc=1">word_small.gif</xsl:when>
<xsl:when test="$visXls=1">xls_small.gif</xsl:when>
<xsl:otherwise>unknown_small.gif</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="ends-with">
<xsl:param name="pEnding"/>
<xsl:value-of select=
"number(substring(.,
string-length() -string-length($pEnding) +1
)
=
$pEnding
)
"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the following test XML document:
<files>
<URLFilePath>myFile.doc</URLFilePath>
<URLFilePath>myFile.xls</URLFilePath>
<URLFilePath>myFile.xls.doc</URLFilePath>
<URLFilePath>myFile.doc.xls</URLFilePath>
</files>
the correct result is produced:
word_small.gif
xls_small.gif
word_small.gif
xls_small.gif
Do note that just using contains() produces incorrect results.
I managed to come up with a solution! Sorry for the late reply but had to work on something else
Here is the code:-
<A target="_blank" style="text-decoration=none">
<xsl:choose>
<xsl:when test="contains(., '.doc')">
<xsl:attribute name="href">viewdoc.aspx?doc=<xsl:value-of select="URLFilePath"/>&mode=inline
</xsl:attribute>
<xsl:attribute name="prefix">
<xsl:value-of select="FileName"/>:
</xsl:attribute>
<IMG src="images/word_small.gif" border="0"/>
</xsl:when>
<xsl:when test="contains(., '.xls')">
<xsl:attribute name="href">viewxls.aspx?doc=<xsl:value-of select="URLFilePath"/>&mode=inline
</xsl:attribute>
<xsl:attribute name="prefix">
<xsl:value-of select="FileName"/>:
</xsl:attribute>
<IMG src="images/excel_small.gif" border="0"/>
</xsl:when>
</xsl:choose>
</A>
Thanks for all your help guys, really very much appreciated!
A late reply but I hit to two answers that deal with matching end of string with XSLT 1.0 and are very elegant:
https://stackoverflow.com/a/3081205/520567
https://stackoverflow.com/a/3081866/520567
go give them +1
This can be done purely in your XSLT document if you require. For displaying the image, you could use a xsl:choose statement, that tests the URLFilePath element
<xsl:choose>
<xsl:when test="contains(., '.doc')">
<IMG src="images/word_small.gif" border="0"/>
</xsl:when>
<xsl:when test="contains(., '.xls')">
<IMG src="images/excel_small.gif" border="0"/>
</xsl:when>
</xsl:choose>
If you wanted to do this check in the code behind, you could always add extra attributes to your URLFilePath element.
imageAttr = xmlDocument.CreateAttr("image")
If correctedPath.ToLower.Contains(".doc") Then
imageAttr.value = "images/word_small.gif"
Else
imageAttr.value = "images/excel_small.gif"
End If
newItemNode.AppendChild(imageAttr)
And then, in your xls, you can simply use this attribute to set the source attribute of the image
<IMG border="0">
<xsl:attribute name="src"><xsl:value-of select='#image' /></xsl:attribute>
</IMG>