What i'm trying to do is to use call-template:SpecialRadio on a Radio elements by looping through each one of them, extracting the data by position and then performing XSLT on them. For some reason, the radio buttons show up, but the Caption data for the StaticLabel is not showing up, i.e. 'Postanschrift' and 'SMS / MMS'. Where did i go wrong in my XSL?
Given jsp-include.xsl
<xsl:template name="SpecialRadio">
<xsl:param name="name"/>
<xsl:param name="map"/>
<xsl:param name="radio"/>
<xsl:param name="radioStyle"/>
<xsl:param name="radioLabel"/>
<xsl:param name="i"/>
<StaticLabel>
<xsl:attribute name="style">
<xsl:copy-of select="$radioStyle[position()=$i]/#style"/>
<xsl:text>; margin-left:500px</xsl:text>
</xsl:attribute>
<xsl:copy-of select="$radioLabel[position()=$i]/#Caption"/>
</StaticLabel>
<Radio>
<ReadOnly>false</ReadOnly>
<Map rtexprvalue="true">mb.getLookup("YES_NO")</Map>
<Name rtexprvalue="true"><xsl:value-of select="$radio/Name"/></Name>
<Default rtexprvalue="true">mb.getValue("<xsl:value-of select="Name"/>")/Default>
</Radio>
</xsl:template>
Given Main.xsl
<div id="head">
<xsl:call-template name="JspInclude">
<xsl:with-param name="flush" select="'true'"/>
<xsl:with-param name="file" select="'Header_1_D.jsp'"/>
</xsl:call-template>
<xsl:for-each select="$radio[position() <= 4]">
<xsl:call-template name="SpecialRadio">
<xsl:with-param name="i" select="position()"/>
<xsl:with-param name="name" select="FieldList[#group='2']/Radio/Name"/>
<xsl:with-param name="map" select="FieldList[#group='2']/Radio/Map"/>
<xsl:with-param name="radio" select="FieldList[#group='2']/Radio"/>
<xsl:with-param name="radioStyle" select="FieldList[#group='2']/StaticLabel"/>
<xsl:with-param name="radioLabel" select="FieldList[#group='2']/StaticLabel"/>
</xsl:call-template>
Given XML
<FieldList group="2">
<StaticLabel style="font-family:Arial;color:#330000;font-size:9pt">
<Caption><![CDATA[Postanschrift]]></Caption>
<Name><![CDATA[APPLICATION_CUSTOMER.APPLICATION_TYPE]]></Name>
</StaticLabel>
<Radio>
<EntityID><![CDATA[6100]]></EntityID>
<Name><![CDATA[APPLICATION_CUSTOMER.APPLICATION_TYPE]]></Name>
<FieldType><![CDATA[]]></FieldType>
<Default rtexprvalue="true"><![CDATA[mb.getValue("APPLICATION_CUSTOMER.APPLICATION_TYPE", "")]]></Default>
<Map rtexprvalue="true"><![CDATA[mb.getLookup("YES_NO", "CODE", "NAME", "EN", false,"")]]></Map>
<ReadOnly rtexprvalue="true"><![CDATA[mb.isReadonly(2)]]></ReadOnly>
<AccessType><![CDATA[2]]></AccessType>
<SearchMatchFlag><![CDATA[]]></SearchMatchFlag>
<InvalidatePlanFlag><![CDATA[false]]></InvalidatePlanFlag>
</Radio>
<StaticLabel style="font-family:Arial;color:#330000;font-size:9pt">
<Caption><![CDATA[SMS / MMS]]></Caption>
<Name><![CDATA[APPLICATION_CUSTOMER.APPLICATION_TYPE]]></Name>
</StaticLabel>
<Radio>
<EntityID><![CDATA[6101]]></EntityID>
<Name><![CDATA[APPLICATION_CUSTOMER.APPLICATION_TYPE]]></Name>
<FieldType><![CDATA[]]></FieldType>
<Default rtexprvalue="true"><![CDATA[mb.getValue("APPLICATION_CUSTOMER.APPLICATION_TYPE", "")]]></Default>
<Map rtexprvalue="true"><![CDATA[mb.getLookup("YES_NO", "CODE", "NAME", "EN", false,"")]]></Map>
<ReadOnly rtexprvalue="true"><![CDATA[mb.isReadonly(2)]]></ReadOnly>
<AccessType><![CDATA[2]]></AccessType>
<SearchMatchFlag><![CDATA[]]></SearchMatchFlag>
<InvalidatePlanFlag><![CDATA[false]]></InvalidatePlanFlag>
</Radio>
</FieldList>
Resulting XSLT using Altova
<div id="head">
<HtmlCode xmlns:jsp="http://www.microforum.com/calms/tags/jsptag-1">
<jsp:include flush="true" page="Header_1_D.jsp"/>
</HtmlCode>
<StaticLabel xmlns:jsp="http://www.microforum.com/calms/tags/jsptag-1" style="; margin-left:500px"/>
<Radio xmlns:jsp="http://www.microforum.com/calms/tags/jsptag-1">
<ReadOnly>false</ReadOnly>
<Map rtexprvalue="true">mb.getLookup("YES_NO")</Map>
<Name rtexprvalue="true"/>
<Default rtexprvalue="true">mb.getValue("APPLICATION_CUSTOMER.APPLICATION_TYPE")</Default>
</Radio>
<StaticLabel xmlns:jsp="http://www.microforum.com/calms/tags/jsptag-1" style="; margin-left:500px"/>
<Radio xmlns:jsp="http://www.microforum.com/calms/tags/jsptag-1">
<ReadOnly>false</ReadOnly>
<Map rtexprvalue="true">mb.getLookup("YES_NO")</Map>
<Name rtexprvalue="true"/>
<Default rtexprvalue="true">mb.getValue("APPLICATION_CUSTOMER.APPLICATION_TYPE")</Default>
</Radio>
<HtmlCode>
<br/>
<br/>
<br/>
</HtmlCode>
</div>
Shouldn't it be along the lines of this -
<xsl:copy-of select="$radioLabel[position()=$i]/Caption"/>
since Caption is an element, not an attribute?
Related
here is my xsl (xslt 1.0)
<tr>
<td align="center" height="60">
<input type="hidden" id="imageA" value="{Item}"/>
<div id="barcode" class="barcode"></div>
</td>
</tr>
The value="{Item}" is a string.
item1;item2;item3;item4;
How to get the 'item3' only?
This will be passed into JavaScript to generate barcode. Currently the barcode is able to show for simple string.
You can use:
substring-before(substring-after(substring-after(Item, ';'), ';'), ';')
to extract the third value of a semicolon separated string.
Alternatively, if using the Xalan-J processor (or another processor supporting the EXSLT str:tokenize() function):
str:tokenize(Item, ';')[3]
XSLT 1.0 allows only immutable variables. You can use recursion on a variable that contains the data of your "value" attribute.
<xsl:template match="/*">
<root>
<xsl:variable name="data" select="td/input/#value"/>
<xsl:call-template name="find">
<xsl:with-param name="count" select="1"/>
<xsl:with-param name="data" select="substring-after($data,';')"/>
<xsl:with-param name="prevData" select="substring-before($data,';')"/>
</xsl:call-template>
</root>
</xsl:template>
<xsl:template name="find">
<xsl:param name="count"/>
<xsl:param name="data"/>
<xsl:param name="prevData"/>
<xsl:if test="$count=3">
<data>
<xsl:value-of select="$prevData"/>
</data>
</xsl:if>
<xsl:if test="$count < 3">
<xsl:call-template name="find">
<xsl:with-param name="count" select="$count+1"/>
<xsl:with-param name="data" select="substring-after($data,';')"/>
<xsl:with-param name="prevData" select="substring-before($data,';')"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
Hope this helps
If third is word isn't what you require everytime then you need the data that tells which word you need and accordingly change the number in find template to suit your need
I asked a similar question earlier. I have made some changes to the code, but am still stuck.
I have part of an XSLT like this:
<xsl:variable name="y" select="0" />
<xsl:if test="units_display='true'">
<xsl:call-template name="DisplayBox">
<xsl:with-param name="current_y" select="$y" />
<xsl:with-param name="value" select="units" />
<xsl:with-param name="text" select="'Units'" />
</xsl:call-template>
</xsl:if>
<xsl:if test="sensor_display='true'">
<xsl:call-template name="DisplayBox">
<xsl:with-param name="current_y" select="$y" />
<xsl:with-param name="value" select="sensor" />
<xsl:with-param name="text" select="'Type'" />
</xsl:call-template>
</xsl:if>
<xsl:if test="offset_display='true'">
<xsl:call-template name="DisplayBox">
<xsl:with-param name="current_y" select="$y" />
<xsl:with-param name="value" select="offset" />
<xsl:with-param name="text" select="'Offset'" />
</xsl:call-template>
</xsl:if>
My call-template is like this:
<xsl:template name="DisplayBox">
<xsl:param name="current_y" />
<xsl:param name="value" />
<xsl:param name="text" />
<rect x="20" y="{150 + $current_y}" width="220" height="20" fill="#FFFFFF" stroke="black" stroke-width="1" />
<text x="25" y="{168 + $current_y}" font-family="arial" font-size="20px" fill="black">
<xsl:value-of select="$value"/>
</text>
<line x1="90" y1="{150 + $current_y}" x2="90" y2="{170 + $current_y}" stroke="black" stroke-width="1" />
<text x="95" y="{168 + $current_y}" font-family="arial" font-size="20px" fill="black"><xsl:value-of select="$text" /></text>
</xsl:template>
I can't work out how to increase the value of current_y depending on whether the if statements are true or not. E,g, if a statement is true, the y value needs to be increased by 20, but not if the statement is false.
So the output could be empty if all 3 statements are false or could be any of these permutations:
Any help would be greatly appreciated.
You have to move the whole thing into a recursion template. You are passing $y for "current_y" which has the value "0" into each call of the template. That recursive template would take the same arguments and two additional:
(1) The test to perform for that round of recursion
(2) Whether you have any additional tests to perform (or exit the recursion)
Then you do a choose and increment the "y" (or not) depending on the test.
* New Info *
After some more thought based on the comments below, what about using something like this:
<xsl:template match="units_display | sensor_display | offset_display">
<xsl:variable name="y-multiplier">
<xsl:value-of select="count(preceding-sibling::units_display[.='true']) + count(preceding-sibling::sensor_display[.='true']) + count(preceding-sibling::offset_display[.='true'])"/>
</xsl:variable>
<xsl:message>
<xsl:value-of select="$y-multiplier"/>
</xsl:message>
</xsl:template>
This counts all of the elements that meet you criteria as you go through the document. This should get you started toward writing the result without recursion.
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
I have xml like
<programs>
<program name="breaking laws" id="97;#ttt;#98;#tpl;#41;#fel" />
<program name="advanced technology" id="89;#hjk;#95;#uio;#81;#lpk" />
<program name="Emerging companies " id="88;#ple;#98;#tpl;#41;#fel" />
<program name="breakinglaws" id="97;#ttt" />
<program name="breakinglaws" id="97;#ttt;#98;#tpl;#81;#lpk" />
<program name="breakinglaws" id="99;#hklo;#95;#uio" />
</programs>
I would like to find all the unique ids text using xslt 1.0 i.e
ttt
tpl
fel
hjk
uio
lpk
ple
hklo
I was trying to do something using key and output tokens
<xsl:template name="output-tokens">
<xsl:param name="list" />
<xsl:variable name="newlist" select="concat(normalize-space($list), ' ')" />
<xsl:variable name="first" select="substring-before($newlist, ';#')" />
<xsl:variable name="remaining" select="substring-after($newlist, ';#')" />
<id>
<xsl:value-of select="$first" />
</id>
<xsl:if test="$remaining">
<xsl:call-template name="output-tokens">
<xsl:with-param name="list" select="$remaining" />
</xsl:call-template>
</xsl:if>
</xsl:template>
Here is one solution
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/programs">
<!-- Variable containing concateneated list of all program elements**
<xsl:variable name="allprograms">
<xsl:apply-templates select="program"/>
</xsl:variable>
<!-- Call recursive template to split the list -->
<xsl:call-template name="output-tokens">
<xsl:with-param name="list" select="$allprograms" />
</xsl:call-template>
</xsl:template>
<!-- Template used to concatenate all program elements -->
<xsl:template match="program">
<xsl:value-of select="concat(#id, ';#') "/>
</xsl:template>
<!-- Recursive template to split out list into unique elements -->
<xsl:template name="output-tokens">
<!-- List to split -->
<xsl:param name="list"/>
<!-- List of all currently processed elements -->
<xsl:param name="newlist" select="';#'" />
<!-- Get first variable in list, and also the remaining part of the list -->
<xsl:variable name="first" select="substring-before($list, ';#')"/>
<xsl:variable name="remaining" select="substring-after($list, ';#')"/>
<!-- Check if first variable is not a number, and is not contained in currently processed list -->
<xsl:if test="number($first) != number($first) and not(contains($newlist, concat(';#', $first, ';#')))">
<id>
<xsl:value-of select="$first"/>
</id>
</xsl:if>
<!-- If there are still elements left in the list, call the template recursively -->
<xsl:if test="$remaining">
<xsl:call-template name="output-tokens">
<xsl:with-param name="list" select="$remaining"/>
<xsl:with-param name="newlist" select="concat($newlist, $first, ';#')"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
The idea is you first build up a single string containing all the program elements concatenated together. You then call a recursive template which gets the first element from the list, and then checks it has not already been processed (this is achieved by the template also containing a variable of already processed elements)
When the XSLT is applied to your sample XML, the following is output:
<id>ttt</id>
<id>tpl</id>
<id>fel</id>
<id>hjk</id>
<id>uio</id>
<id>lpk</id>
<id>ple</id>
<id>hklo</id>
Is it possible to access child node attributes in xsl:if
I have to convert that Xml to text file
<Report>
<Total>
<RecordValues>
<Record>
<FieldValue fieldName="index" fieldValue="1" />
<FieldValue fieldName="dtrk_sysid" fieldValue="0"/>
<FieldValue fieldName="version" fieldValue="100" />
<FieldValue fieldName="user" fieldValue="tester" />
<FieldValue fieldName="date_modified" fieldValue="2010-10-18 12:18:12" />
<FieldValue fieldName="object_name" fieldValue="Menu" />
<FieldValue fieldName="permission" fieldValue="Permission X" />
</Record>
<Record>
<FieldValue fieldName="index" fieldValue="2" />
<FieldValue fieldName="dtrk_sysid" fieldValue="55555"/>
<FieldValue fieldName="version" fieldValue="100" />
<FieldValue fieldName="user" fieldValue="user1" />
<FieldValue fieldName="date_modified" fieldValue="2010-12-15 12:18:12" />
<FieldValue fieldName="object_name" fieldValue="Control" />
<FieldValue fieldName="permission" fieldValue="Permission E" />
</Record>
<Record>
<FieldValue fieldName="index" fieldValue="3" />
<FieldValue fieldName="dtrk_sysid" fieldValue="55555"/>
<FieldValue fieldName="version" fieldValue="15" />
<FieldValue fieldName="user" fieldValue="user2" />
<FieldValue fieldName="date_modified" fieldValue="2010-10-02 12:18:12" />
<FieldValue fieldName="object_name" fieldValue="Run" />
<FieldValue fieldName="permission" fieldValue="Permission R" />
</Record>
</RecordValues>
</Total>
I already know how to do that, but the file must have header record which is should appear only once as the first record of the file. It must contains some default values and some values from FieldValue node.
Here is the example of header record:
HDRTT55555EE000KK20101018UU
1 100 101810
tester Menu Permission X
2 100 121510
user1 Control Permission E
3 15 100210
user2 Run Permission R
Here is what I've done so far:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" indent="yes" encoding="UTF-8" omit-xml- declaration="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="/Report/Total/RecordValues"/>
<xsl:apply-templates select="/Report/Total/RecordValues/Record/FieldValue"/>
</xsl:template>
<xsl:template match="RecordValues">
<xsl:text>HDR</xsl:text>
<xsl:text>TT</xsl:text>
<xsl:variable name="fvsys" select="Record/FieldValue[#fieldName = 'dtrk_sysid']"/>
<xsl:choose>
<xsl:when test="$fvsys/#fieldValue != '0'">
<xsl:value-of select="$fvsys/#fieldValue"/>
</xsl:when>
<xsl:otherwise>
<xsl:text>12343</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:text>EE</xsl:text>
<xsl:text>000</xsl:text>
<xsl:text>KK</xsl:text>
<xsl:if test="Record/FieldValue[#fieldName='date_modified']">
<xsl:call-template name="ppad">
<xsl:with-param name="str" select="concat(substring(translate(Record/FieldValue[#fieldName = 'date_modified']/#fieldValue,'-',''),5,4), substring(Record/FieldValue[#fieldName = 'date_modified']/#fieldValue,3,2))"/>
<xsl:with-param name="len" select="6"/>
</xsl:call-template>
</xsl:if>
<xsl:text>UU</xsl:text>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="FieldValue">
</xsl:template>
<xsl:template name="ppad">
<xsl:param name="str"/>
<xsl:param name="chr" select="' '"/>
<xsl:param name="len" select="0"/>
<xsl:choose>
<xsl:when test="string-length($str) < $len">
<xsl:call-template name="ppad">
<xsl:with-param name="str" select="concat($str, $chr)"/>
<xsl:with-param name="len" select="$len"/>
<xsl:with-param name="chr" select="$chr"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$str"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Thanks for your help.
The main problem with the following if statement:
<xsl:if test="Record/FieldValue/#fieldName='dtrk_sysid' and Record/FieldValue/#fieldValue!='0'">
<xsl:value-of select="Record/FieldValue/#fieldValue"/>
</xsl:if>
is that the #fieldValue you're trying to compare after the and is supposed to be the #fieldValue of the <FieldValue> whose #fieldName is 'dtrk_sysid', but there is nothing that limits the second comparison to that particular <FieldValue>. The <xsl:if test=...> does not set a context. <xsl:value-of> will then select the first #fieldValue attribute of all Record/FieldValue nodes under the context node, which by luck happens to be the right one, in your sample input XML (but maybe not always?).
To fix that, you can capture the context (the <FieldValue> whose #fieldName is 'dtrk_sysid') in a variable:
<xsl:variable name="fvsys" select="(Record/FieldValue[#fieldName = 'dtrk_sysid'])[1]"/>
Then you can replace your first two if statements with:
<xsl:choose>
<xsl:when test="$fvsys/#fieldValue != '0'">
<xsl:value-of select="$fvsys/#fieldValue"/>
</xsl:when>
<xsl:otherwise>
<xsl:text>12343</xsl:text>
</xsl:otherwise>
</xsl:choose>
(The above has been modified to fit the behavior described in comments.)
You can replace your third if statement with:
<xsl:value-of select="(Record/FieldValue[#fieldName = 'date_modified'])[1]/#fieldValue"/>
This will not output anything if no such FieldValue exists.
If after this you're still not getting the desired output, tell us what output you are getting, and how it differs from the desired output.