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
Related
Needs some help. In umbraco I have my tree like this
-First
- page 1
- page 2
- page 3
- page 4
- page 5
- page 6
- page 7
- page 8
- page 9
- page 10
- page 11
- page 12...
looping all the pages i filter them.
So I apply my xslt only to pages 4,7,10
position() will give me 4,7,10
How can I count the number of pages i walked through? (in this example 3)
Here's my xslt:
<xsl:param name="currentPage"/>
<xsl:variable name="root" select="$currentPage/ancestor-or-self::* [#isDoc][last()]"/>
<xsl:variable name="articles" select="$root/descendant-or-self::* [#isDoc][#level=2]"/>
<xsl:template match="/">
<xsl:for-each select="$articles">
<xsl:if test="./* [#isDoc and string(umbracoNaviHide)!='1' and local-name(current())='myfilteredpage']">
...some html construction...
</xsl:if>
</xsl:for-each>
</xsl:template>
Thank you for your help.
Benjamin
PS: found those link that helped me to build the pagination but my counter isn't resolved
first link
second link
you can count the total number of pages you walk through like this:
count($articles/* [#isDoc and string(umbracoNaviHide)!='1' and local-name(current())='myfilteredpage'])
If you would like to have current 'count' inside your loop, you should change your xsl like this:
<xsl:param name="currentPage"/>
<xsl:variable name="root" select="$currentPage/ancestor-or-self::* [#isDoc][last()]"/>
<xsl:variable name="articles" select="$root/descendant-or-self::* [#isDoc][#level=2]"/>
<xsl:template match="/">
<xsl:variable name="articlesToLoop" select="$articles//* [#isDoc and string(umbracoNaviHide)!='1' and local-name(current())='myfilteredpage']" />
<xsl:for-each select="$articlesToLoop">
Current count: <xsl:value-of select="position()" />
- <xsl:value-of select="#nodeName" />
</xsl:for-each>
</xsl:template>
I've tried the counter you give... The counter show 0 when it needs to show 2.
I've found another behaviour of my xsl that is not clear. Only when my page as at least 1 child publish it shows me the page.
Here is my xslt code
<xsl:param name="currentPage"/>
<xsl:variable name="root" select="$currentPage/ancestor-or-self::* [#isDoc][last()]"/>
<xsl:variable name="articles" select="$root/descendant::* [#isDoc][#level=2]"/>
<xsl:variable name="NumberOfCharactersToShow" select="number(400)"/>
<xsl:template match="/">
<!-- start writing XSLT -->
<xsl:variable name="counter" select="count($articles//* [#isDoc and string(umbracoNaviHide)!='1' and local-name(current())='Article'])" />
<xsl:value-of select="$counter" />
<xsl:for-each select="$articles">
<xsl:variable name="article" select="* [#isDoc and string(umbracoNaviHide)!='1' and local-name(current())='Article']" />
<xsl:if test="$article">
<xsl:call-template name="article" />
<!--<xsl:for-each select="current()/descendant::* [#isDoc]">
<xsl:call-template name="article" />
</xsl:for-each>-->
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template name="article">
<xsl:variable name="text" select="umbraco.library:StripHtml(umbraco.library:TruncateString(bodyText,$NumberOfCharactersToShow,'...'))"/>
<!--article-->
<div class="article border border-radius border-shadow">
<div class="atitle">
<p><xsl:value-of select="title" /></p>
</div>
<div class="atext">
<p><xsl:value-of select="$text" /></p>
</div>
</div>
</xsl:template>
Try to explain. Here is my example tree
-first page
-page
-article1 (published)
-article2 (unpublished)
-article3 (unpublished)
-page
-page
-page
-article4 (published)
-page
-article5 (published)
-article6 (published)
-article7 (unpublished)
-page...
actually my code will create only article5 (the children (article6,7) creation is in xslt comments)
But as you can see article1 and article4 are not created...I don't understand why...
Thanks for your help.
Benjamin
following is my code where i want to give the hidden variable and assign the value for it to access later.
<xsl:for-each select="//Root/Record">
<xsl:if test="(#CIMtrek_accountlist_customer_number != '') ">
<option style="padding:5px;">
<xsl:attribute name="class">>
<xsl:choose>
<xsl:when test="(position() mod 2) = 0">
AlternateRowOne
</xsl:when>
<xsl:otherwise>
AlternateRowTwo
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
// here i want to set hidden varialble and assign the value for it
<xsl:attribute name="value">
<xsl:value-of
select="#CIMtrek_accountlist_customer_number" /></xsl:attribute>
<xsl:value-select="#CIMtrek_accountlist_customer_number" />
</option>
</xsl:if>
</xsl:for-each>
the variable name will be some thing similar to like this
<input type="hidden"
name="hdnDialogListCtrlPlaceholder_CIMtrek_DailyshipCo_Destination_"+i
id="hdnDialogListCtrlPlaceholder_CIMtrek_DailyshipCo_Destination_"+i
/>
where i =0
and i++;
name_1
name_2
name_n
is it possible to use : <FieldRef Name="<FieldInternalName>" Explicit="TRUE"/>
how to do this in xsl
I typically achieve recursion in the following manner.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<xsl:call-template name="recur">
<xsl:with-param name="max_recursions" select="5"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="recur">
<xsl:param name="n">0</xsl:param>
<xsl:param name="max_recursions"/>
REPEATING UNIT HERE
<xsl:if test="$max_recursions != $n">
<xsl:call-template name="recur">
<xsl:with-param name="n" select="$n + 1"/>
<xsl:with-param name="max_recursions" select="$max_recursions"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
It isn't often advised though and you can usually achieve much faster, more succinct and more readable code through a well constructed XPath.
You're trying to write procedural code in XSLT, and that won't work. If you explain what transformation you want to perform (what's the input, what's the output, and how are they related?) then we can show you how to do it "the XSLT way", that is, declaratively.
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>
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
I am currently trying to generate the creation SQL for my tables based off of a Visio diagram. I am doing this using the approach found here.
http://www.dougboude.com/blog/1/2008/11/SQL-Forward-Engineering-with-Visio-2003-Professional.cfm
I am attempting to modify the xslt file found there to better model the syntax that we use in our office. Unfortunately, I cannot get the part that involves passing the table name into the template for the table columns to work. The template gets called, but it seems to ignore my parameters.
<xsl:template match="Entity" mode="table">
IF NOT EXISTS (SELECT * FROM sysobjects WHERE name = '<xsl:value-of select="#PhysicalName"/>')
<br />
CREATE TABLE dbo.[<xsl:value-of select="#PhysicalName"/>]
(
<br />
<xsl:for-each select="EntityAttributes/EntityAttribute">
<span style="padding-left: 20px;">
<xsl:apply-templates select="../../../../Attributes/Attribute[#AttributeID = current()/#EntityAttributeID]" mode="table">
<xsl:with-param name="EntityName" select="#PhysicalName" />
</xsl:apply-templates>
</span>
<xsl:if test="count(../../EntityAttributes/EntityAttribute) != position()">,</xsl:if>
<br />
</xsl:for-each>
)
<br />
GO
<p />
<xsl:apply-templates select="EntityAnnotations/EntityAnnotation[#AnnotationType='Primary Key']" mode="pk"/>
<xsl:apply-templates select="EntityAnnotations/EntityAnnotation[#AnnotationType='Alternate Key']" mode="ak"/>
<xsl:apply-templates select="EntityAnnotations/EntityAnnotation[#AnnotationType='Index']" mode="idx"/>
</xsl:template>
<!-- Create column for each EntityAttribute -->
<xsl:template match="Attribute" mode="table">
<xsl:param name="EntityName"></xsl:param>
<xsl:variable name="nullability">
<xsl:choose>
<xsl:when test='#AllowNulls = "false"'>NOT NULL CONSTRAINT DF_<xsl:value-of select="$EntityName" />_<xsl:value-of select="#PhysicalName"/>
</xsl:when>
<xsl:otherwise> NULL</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="incremental">
<xsl:choose>
<xsl:when test='#PhysicalDatatype = "int identity"'> INT IDENTITY(1,1)</xsl:when>
<xsl:otherwise><xsl:value-of select="#PhysicalDatatype"/></xsl:otherwise>
</xsl:choose>
</xsl:variable>
[<xsl:value-of select="#PhysicalName"/>] <span style="text-transform:uppercase;"> <xsl:value-of select="$incremental"/></span> <xsl:value-of select="$nullability"/>
</xsl:template>
The parameter is not ignored, but I guess it is empty. You call:
<xsl:with-param name="EntityName" select="#PhysicalName" />
where #PhysicalName must be an attribute of EntityAttributes/EntityAttribute element from the for-each. The fact that you use #PhysicalName earlier in
CREATE TABLE dbo.[<xsl:value-of select="#PhysicalName"/>]
makes me think in reality it is an attribute of the Entity element the template matches. You need to store its value in a variable first (before the for-each):
<xsl:variable name="PhysicalName" select="#PhysicalName" />
and then use it like this:
<xsl:with-param name="EntityName" select="$PhysicalName" />
<!-- -------------------------------------^ -->
The for-each resets the context node with every iteration, I guess this is where it goes wrong for you.