Set input value from substring - xslt

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

Related

Sum value of output of template in Apache FOP

I am using Apache FOP to generate a PDF document, and to display a certain value I have to iterate over a number of nodes to determine a total price value, then sum that value. So far I have a function that iterates over an array and then retrieves the intended value, but the issue occurs when I try to sum the results.
<xsl:function name="foo:buildTotalValue">
<xsl:param name="items" />
<xsl:variable name="totals">
<xsl:for-each select="$items/charge">
<xsl:call-template name="getTotalPriceNode">
<xsl:with-param name="itemParam" select="." />
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:value-of select="sum(exsl:node-set($totals))" />
</xsl:function>
<xsl:template name="getTotalPriceNode">
<xsl:param name="itemParam" />
<xsl:choose>
<xsl:when test="$itemParam/Recurrance = 'OnceOff'">
<xsl:value-of select="$itemParam/TotalValue" />
</xsl:when>
<xsl:when test="$itemParam/Recurrance = 'Monthly'">
<xsl:value-of select="$itemParam/TotalValue * $itemParam/Months"/>
</xsl:when>
<xsl:otherwise><xsl:value-of select="0" /></xsl:otherwise>
</xsl:choose>
</xsl:template>
I'm hoping that when I pass in foo:buildTotalValue with entries like this:
<Charges>
<Charge>
<Recurrance>OnceOff</Recurrance>
<TotalValue>50.00</TotalValue>
</Charge>
<Charge>
<Recurrance>Monthly</Recurrance>
<TotalValue>10.00</TotalValue>
<Months>6</Months>
</Charge>
</Charges>
would return with the value 110.00, but instead I get the error:
Cannot convert string "50.0060.00" to double
I've tried adding a <value> or something in the templates and then using that as a selector for the exsl:node-set function but it doesn't seem to make a difference.
AFAICT, the problem with your function is that it builds a concatenated string of values returned by the called template, instead of a tree of nodes that can be converted into a node-set and summed.
Try changing:
<xsl:for-each select="$items/charge">
<xsl:call-template name="getTotalPriceNode">
<xsl:with-param name="itemParam" select="." />
</xsl:call-template>
</xsl:for-each>
to:
<xsl:for-each select="$items/charge">
<total>
<xsl:call-template name="getTotalPriceNode">
<xsl:with-param name="itemParam" select="." />
</xsl:call-template>
</total>
</xsl:for-each>
and:
<xsl:value-of select="sum(exsl:node-set($totals))" />
to:
<xsl:value-of select="sum(exsl:node-set($totals)/total)" />
Untested, because (see comment to your question).
I ended up using the suggestion from Martin from the comment - the xpath 2+ expression along the line of:
sum(Charge[Recurrance = 'OnceOff']/TotalValue | Charge[Recurrance = 'Monthly']/(TotalValue * Months))
which was able to achieve what I needed without the use of functions / templates / node-set (And in a lot less code)

Compare xml node values in xsl and highlight differences

I have an xml. I am transforming it using xsl stylesheet and showing in html page using java. My requirement is , I need to compare two node values and if there is a difference, I need to highlight the changed character value. How can this be done ?
XML :
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Message>
<DiffDetailMessage>
<TestCaseID>000001</TestCaseID>
<res1>VI7002 1D</res1>
<res2>VI7002 DD </res2>
</DiffDetailMessage>
<DiffDetailMessage>
<TestCaseID>000002</TestCaseID>
<res1>BS7002 1D</res1>
<res2>BS7002 SS </res2>
</DiffDetailMessage>
</Message>
XSL :
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<h2>Report</h2>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="Message/DiffDetailMessage">
<table border="2">
<xsl:apply-templates select="TestCaseID"/>
<xsl:apply-templates select="res1"/>
<xsl:apply-templates select="res2"/>
</table>
</xsl:template>
<xsl:template match="TestCaseID">
<tr><td><b>Test CaseID </b></td>
<td><xsl:value-of select="."/></td></tr>
</xsl:template>
<xsl:template match="res1">
<tr><td><b>Res1</b></td>
<td><xsl:value-of select="."/> </td> </tr>
</xsl:template>
<xsl:template match="res2">
<tr><td><b>Res2</b></td>
<td><xsl:value-of select="."/></td> </tr>
</xsl:template>
</xsl:stylesheet>
How can I compare node values res1 with res2 ? In my case, value of "VI70002 ID" should be compared against "VI7002 DD" and since there is a change, I should highlight "D" character in html page using xsl. Can someone help on this regard.
If you are using only XSLT-1.0, you can use a recursive named template to iterate over the string char-by-char: the following template takes two strings as input and puts a bold emphasis on each different char. If the second string is longer than the first one, these trailing chars are highlighted, too.
<xsl:template name="cmp">
<xsl:param name="str1" />
<xsl:param name="str2" />
<xsl:choose>
<xsl:when test="substring($str1,1,1) = substring($str2,1,1)">
<xsl:value-of select="substring($str2,1,1)"/>
</xsl:when>
<xsl:when test="substring($str1,1,1) != substring($str2,1,1)">
<b><xsl:value-of select="substring($str2,1,1)"/></b>
</xsl:when>
<xsl:when test="$str1 = '' and substring($str2,1,1)">
<b><xsl:value-of select="substring($str2,1,1)"/></b>
</xsl:when>
</xsl:choose>
<xsl:if test="string-length($str1) > 0 or string-length($str2) > 0">
<xsl:call-template name="cmp">
<xsl:with-param name="str1" select="substring($str1,2)" />
<xsl:with-param name="str2" select="substring($str2,2)" />
</xsl:call-template>
</xsl:if>
</xsl:template>
Call this template from one of the other templates to get a (partially) highlighted "string", e.g.
<xsl:template match="res2">
<tr><td><b>Res2</b></td>
<td>
<xsl:call-template name="cmp">
<xsl:with-param name="str1" select="../res1" />
<xsl:with-param name="str2" select="." />
</xsl:call-template>
</td> </tr>
</xsl:template>

how to set a variable name dynamic in xsl

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.

Print the same value many times in xslt

I have the variable x which is a number. I have a line. ("<name>James</name>") I need to print this sentence number x times. Can I do it in an easy way? without being complex?
If you are using XSLT 2.0 then you can do this ...
<xsl:for-each select="for $i in 1 to $x return $i">
<name>James</name>
</xsl:for-each>
The following is untested...
<xsl:call-template name="show">
<xsl:with-param name="text"><name>James</name></xsl:with-param>
<xsl:with-param name="count">50</xsl:with-param>
</xsl:call-template>
<xsl:template name="show">
<xsl:param name="text"/>
<xsl:param name="count"/>
<xsl:value-of select="$text"/>
<xsl:if test="number($count)>0">
<xsl:call-template name="show">
<xsl:with-param name="text" select="$text"/>
<xsl:with-param name="count" select="number($count)-1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
Updated to have <name> and </name>.
Here is an XmlPlayground of the above working
You could adding the following somewhere in your stylesheet:
<mydata>
<x/><x/><x/><x/> <!-- to print four times -->
</mydata>
then
<xsl:for-each select="document()//mydata/x">
<name>James</name>
</xsl:for-each>
This takes advantage of the ability to include your own data in an XSLT program, and access it through the document function (no argument indicates the stylesheet itself).

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