XSL checking integer - xslt

How to check the integer value in XSL? I'm using version 1.0
This is what I've tried, but it's not working:
<xsl:variable name="ShowEmailEventId"
select="com.zoniac.emailevent.NewEmailEventBean/emailEventIdString"/>
<xsl:if test="$ShowEmailEventId !=48">
<table align="center"
width="96%"
border="1"
style="border-color:#2E73AD;border-collapse:collapse"
cellspacing="0"
cellpadding="10">
<tr>
<td width="10%"
style="border-color:#2E73AD;color: black; font: 11px verdana;padding:2px"
align="left"
valign="top">
<b>S.No</b>
</td>
</tr>
</table>
</xsl:if>

This is probably the shortest expression, returning true() iff $x can be used as an integer:
Just use:
floor($x) = $x
The full test will be:
<xsl:if test="floor($x) = $x">
<!-- $x is an integer -->
</xsl:if>
or
<xsl:when test="floor($x) = $x">
<!-- $x is an integer -->
</xsl:when>
or
someXPathExpression[floor($x) = $x]

TO check if a value nameofint is an int... (you are obviously going to want to change the inside of the if condition.
<xsl:template match="CheckInt">
<xsl:if test="not(string(.) castable as xs:integer)">
<xsl:text>NOT AN INT: </xsl:text>
<xsl:value-of select="."/>
</xsl:if>
</xsl:template>

Related

XSLT Count using variable and for-each

I am trying to get the count using the for-each and counter variable but I am getting an incorrect values. Any help with this would be great.
XML
<ProjectFileManagers>
<ProjectFileManagers>
<ProjectFileManagerId>34</ProjectFileManagerId>
<ProjectId>39352</ProjectId>
<FileManagerId>11</FileManagerId>
</ProjectFileManagers>
<ProjectFileManagers>
<ProjectFileManagerId>35</ProjectFileManagerId>
<ProjectId>39352</ProjectId>
<FileManagerId>12</FileManagerId>
</ProjectFileManagers>
</ProjectFileManagers>
XSLT
<tr>
<td colspan="5">
<span class="title">
<xsl:text>Material Attached</xsl:text>
</span>
<br />
<xsl:variable name="materialCount" select="0"></xsl:variable>
<xsl:for-each select="ProjectFileManagers/ProjectFileManagers/ProjectFileManagerId">
<xsl:value-of select="$materialCount + 1"/>
</xsl:for-each>
<xsl:value-of select="$materialCount" disable-output-escaping="yes" />
</td>
</tr>
in stead of
<xsl:value-of select="$materialCount + 1"/>
use:
<xsl:value-of select="position()"/>

XSLT: Count the iteration of a cases inside a loop

I have two loops and want to count the iteration of cases OK and NotOK and overall cases inside xslt file.
How I cold do so? If I want to know the sum of both iteration how could I write it?
my For loops are as:
<xsl:for-each select="test">
<xsl:variable name="LinkName" select="attribute::name"/>
<tr>
<th style="text-align:left;vertical-align:top;position:"><a name="{$LinkName}"><xsl:value-of select="$LinkName"/></a></th>
<xsl:for-each select="descendant::node()">
<xsl:choose>
<xsl:when test="attribute::state='NotOK'">
<tr>
<td bgcolor="red"><xsl:value-of select="description"/></td>
</tr>
</xsl:when>
<xsl:when test="attribute::state='OK'">
<tr>
<td bgcolor="lime"><xsl:value-of select="description"/></td>
</tr>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</tr>
</xsl:for-each>
Update:
<table>
<tr bgcolor="coral">
<th>Test cases</th>
<th>Info</th>
</tr>
<xsl:for-each select="test">
<xsl:variable name="Summation"/>
<xsl:variable name="LinkIt" select="#name"/>
<xsl:choose>
<xsl:when test="descendant::node()/#state='NotOK'">
<tr>
<td bgcolor="red"><xsl:value-of select="$LinkIt"/></td>
<td>
<xsl:value-of select="count(descendant::node()[#state='NotOK'])"/> of <xsl:value-of select="count(descendant::node()[#state='OK']) + count(descendant::node()[#state='NotOK'])"/>
</td>
</tr>
</xsl:when>
<xsl:when test="descendant::node()/attribute::state='OK'">
<tr>
<td bgcolor="lime"><xsl:value-of select="$LinkIt"/></td>
<td>
---
</td>
</tr>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</table>
for-each is not a loop. If you want to count all descendant nodes of the test elements then simply use <xsl:value-of select="count(test/descendant::node())"/>. You can also add predicates to XPath expressions, like count(test/descendant::node()[attribute::state='NotOK']).
Inside of a <xsl:for-each select="test"> the context node is a test element so any count expression should be relative to that e.g. count(descendant::node()[attribute::state='NotOK']).

Arithmetic operation does not work when used in with-param in xsl

Could someone please explain why the following does not work.
Here is the xml:
<?xml version="1.0" ?>
<testsuites>
<testsuite errors="0" failures="0" name="test_ui_orchestration" tests="10" time="90.190"/>
<testsuite errors="1" failures="0" name="test_ui_tables" tests="13" time="1115.771"/>
<testsuite errors="0" failures="3" name="test_ui_dashboard" tests="18" time="116.397"/>
</testsuites>
I want to calculate total number of tests, total pass and fail. I have a problem getting total number of failures (failures + errors) and total number of pass (for simplicity: tests - failures). I call the same xml-template for calculating totals passing in different values using "with-param" as follows (section within "Calculate sums" comments):
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/testsuites">
<html>
<body>
<!-- Calculate sums start -->
<xsl:variable name="allSum">
<xsl:call-template name="testsSum">
<xsl:with-param name="numTests" select="testsuite/#tests"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="failedSum">
<xsl:call-template name="testsSum">
<xsl:with-param name="numTests" select="testsuite/#failures"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="errorSum">
<xsl:call-template name="testsSum">
<xsl:with-param name="numTests" select="testsuite/#errors"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="failederrorSum">
<xsl:call-template name="testsSum">
<xsl:with-param name="numTests" select="testsuite/#failures + testsuite/#errors"/>
</xsl:call-template>
</xsl:variable>
<!-- Calculate sums ends -->
<h2>Test Results</h2>
<table border="1">
<tr bgcolor="#9acd32">
<th>Test Area</th>
<th>Total</th>
<th>Pass</th>
<th>Fail</th>
<th>Error</th>
<th>Fail and Error</th>
</tr>
<xsl:for-each select="testsuite">
<tr>
<td><xsl:value-of select="#name"/></td>
<td><xsl:value-of select="#tests"/></td>
<td><xsl:value-of select="#tests - (#failures + #errors)"/></td>
<td><xsl:value-of select="#failures"/></td>
<td><xsl:value-of select="#errors"/></td>
<td><xsl:value-of select="#failures + #errors"/></td>
<td> </td>
</tr>
</xsl:for-each>
<tr>
<td><b>All Tests</b></td>
<td><xsl:value-of select="$allSum"/></td>
<td>foo</td>
<!--
<td><xsl:value-of select="$passedSum"/></td>
-->
<td><xsl:value-of select="$failedSum"/></td>
<td><xsl:value-of select="$errorSum"/></td>
<td><xsl:value-of select="$failederrorSum"/></td>
<td></td>
</tr>
</table>
</body>
</html>
</xsl:template>
<xsl:template name="testsSum">
<xsl:param name="numTests"/>
<xsl:choose>
<xsl:when test="$numTests">
<xsl:variable name="recursive_result">
<xsl:call-template name="testsSum">
<xsl:with-param name="numTests" select="$numTests[position() > 1]"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="number($numTests[1]) + $recursive_result"/>
</xsl:when>
<xsl:otherwise><xsl:value-of select="0"/></xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
This produces the following output for the sums (full output is at the end of this post):
41 3 1 0
while it should be:
41 3 1 4
Each individual sum works fine, the corresponding attribute is found. However, when I attempt to add two attributes and pass that to the sum template, it does not work as expected.
It gets worse. The code for generating total passed tests is:
<xsl:variable name="passedSum">
<xsl:call-template name="testsSum">
<xsl:with-param name="numTests"
select="testsuite/#tests - testsuite/#failures"/>
</xsl:call-template>
</xsl:variable>
When the above code is enabled, I get the following error:
Failed to evaluate the expression of variable 'numTests'
I've been searching online and understand that the "select" of "with-param" accepts "An XPath expression that defines the value of the parameter" (from w3schools). An XPath expression can contain arithmetic operations (http://www.w3schools.com/xpath/xpath_operators.asp), so why do the above fail?
Here is full output of the xsl transformation:
Test Area Total Pass Fail Error Fail and Error
----------------------------------------------------------------------
test_ui_orchestration 10 10 0 0 0
test_ui_tables 13 12 0 1 1
test_ui_dashboard 18 15 3 0 3
----------------------------------------------------------------------
All Tests 41 foo 3 1 0
Here is the expected output of the xsl transformation (modified values marked with *):
Test Area Total Pass Fail Error Fail and Error
----------------------------------------------------------------------
test_ui_orchestration 10 10 0 0 0
test_ui_tables 13 12 0 1 1
test_ui_dashboard 18 15 3 0 3
----------------------------------------------------------------------
All Tests 41 37* 3 1 4*
As Stormtroopr says, you haven't shown us the part of the XSLT code that sets the context, and the fact that you left this out suggests you haven't understood how important context is in XSLT. If your XPath expressions select anything at all, we can probably assume that the context item is the testsuites element, in which case path expressions such as testsuite/#failures all select multiple values (a node set containing several attribute nodes). That's fine if the template you are calling expects a node-set. But when you use a node-set containing multiple nodes as input to an arithmetic operation, then:
(a) In XSLT 1.0 it uses the first node in the node-set and ignores the others
(b) In XSLT 2.0 you get a type error saying that what you are doing makes no sense.
Since you're getting an error, I assume you are using XSLT 2.0, though it doesn't seem a very helpful error message (which XSLT processor are you using?)
As for fixing the problem, I can't help with that because you haven't explained what you are trying to achieve - I can't reverse-engineer the requirements from incorrect code.
Since the question has changed dramatically, I've made a new answer.
Your summing template (in fact most of the template) works fine. All you need to do to get those totals down the bottom, you just need to perform addition/subtraction on the variables you've already created:
<xsl:variable name="failederrorSum" select="$failedSum + $errorSum" />
<xsl:variable name="passedSum" select="$allSum - $failederrorSum" />
This stylesheet applied to the input XML:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/testsuites">
<html>
<body>
<!-- Calculate sums start -->
<xsl:variable name="allSum">
<xsl:call-template name="testsSum">
<xsl:with-param name="numTests" select="testsuite/#tests"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="failedSum">
<xsl:call-template name="testsSum">
<xsl:with-param name="numTests" select="testsuite/#failures"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="errorSum">
<xsl:call-template name="testsSum">
<xsl:with-param name="numTests" select="testsuite/#errors"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="failederrorSum" select="$failedSum + $errorSum" />
<xsl:variable name="passedSum" select="$allSum - $failederrorSum" />
<!-- Calculate sums ends -->
<h2>Test Results</h2>
<table border="1">
<tr bgcolor="#9acd32">
<th>Test Area</th>
<th>Total</th>
<th>Pass</th>
<th>Fail</th>
<th>Error</th>
<th>Fail and Error</th>
</tr>
<xsl:apply-templates />
<tr>
<td><b>All Tests</b></td>
<td><xsl:value-of select="$allSum"/></td>
<td><xsl:value-of select="$passedSum"/></td>
<td><xsl:value-of select="$failedSum"/></td>
<td><xsl:value-of select="$errorSum"/></td>
<td><xsl:value-of select="$failederrorSum"/></td>
<td></td>
</tr>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="testsuite">
<tr>
<td><xsl:value-of select="#name"/></td>
<td><xsl:value-of select="#tests"/></td>
<td><xsl:value-of select="#tests - (#failures + #errors)"/></td>
<td><xsl:value-of select="#failures"/></td>
<td><xsl:value-of select="#errors"/></td>
<td><xsl:value-of select="#failures + #errors"/></td>
<td> </td>
</tr>
</xsl:template>
<xsl:template name="testsSum">
<xsl:param name="numTests"/>
<xsl:choose>
<xsl:when test="$numTests">
<xsl:variable name="recursive_result">
<xsl:call-template name="testsSum">
<xsl:with-param name="numTests" select="$numTests[position() > 1]"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="number($numTests[1]) + $recursive_result"/>
</xsl:when>
<xsl:otherwise><xsl:value-of select="0"/></xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Gives this output:
<html>
<body>
<h2>Test Results</h2>
<table border="1">
<tr bgcolor="#9acd32">
<th>Test Area</th>
<th>Total</th>
<th>Pass</th>
<th>Fail</th>
<th>Error</th>
<th>Fail and Error</th>
</tr>
<tr>
<td>test_ui_orchestration</td>
<td>10</td>
<td>10</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>
</td>
</tr>
<tr>
<td>test_ui_tables</td>
<td>13</td>
<td>12</td>
<td>0</td>
<td>1</td>
<td>1</td>
<td>
</td>
</tr>
<tr>
<td>test_ui_dashboard</td>
<td>18</td>
<td>15</td>
<td>3</td>
<td>0</td>
<td>3</td>
<td>
</td>
</tr>
<tr>
<td>
<b>All Tests</b>
</td>
<td>41</td>
<td>37</td>
<td>3</td>
<td>1</td>
<td>4</td>
<td/>
</tr>
</table>
</body>
</html>
Which looks like this:
Unfortunately, you've only posted fragments of your XSLT, but I believe the problem is that you are calling testsuite/#failures from the testsuites element.
Rather than returning a number, this is instead returning either a result tree fragment or node-set with the values of the failures attribute for each testsuite element.
As such the traditional numeric operations are failing, as they expect a number and get an RTF or nodeset instead, and attempt to apply the operation giving an unexpected result.
Without knowing what the rest of the code is, I'd suggest the way to fix is to wrap the variable instantiations either in a for-each loop, or even better, in a template that matches on an individual testsuite.

Alternate Row Color of Table using XSLT

I have an XSLT where I want to alternate the row colors of an output table. I know that you can use the code such as in this example:
<table>
<tr>
<td>Name</td>
<td>ID</td>
</tr>
<xsl:for-each select="//Book">
<xsl:variable name="altColor">
<xsl:choose>
<xsl:when test="position() mod 2 = 0">#FFFFFF</xsl:when>
<xsl:otherwise>#D3DFEE</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<tr bgcolor="{$altColor}">
<td><xsl:value-of select="current()/#name"/></td>
<td><xsl:value-of select="current()/#ID"/></td>
</tr>
</xsl:for-each>
</table>
which works fine however, I have a few instances where I need to include some if statements within the for-each, such as.
<table>
<tr>
<td>Name</td>
<td>ID</td>
</tr>
<xsl:for-each select="//Book">
<xsl:variable name="altColor">
<xsl:choose>
<xsl:when test="position() mod 2 = 0">#FFFFFF</xsl:when>
<xsl:otherwise>#D3DFEE</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:if test="current()/#ID > 10000 and current/#ID < 6000">
<tr bgcolor="{$altColor}">
<td><xsl:value-of select="current()/#name"/></td>
<td><xsl:value-of select="current()/#ID"/></td>
</tr>
</xsl:if>
</xsl:for-each>
</table>
Then it doesn't work because it may skip an item at a position in the for-each and I end up with randomly alternating row colors or it may start at an incorrect position where the rows alternate starting with the incorrect color.
I've tried adding an xsl:sort, which doesn't really fix the problem. Is there a way to avoid this snag?
Try with the following code:
tr[position() mod 2 =0]
<xsl:template match="n1:tr[position() mod 2 =0]">
<tr bgcolor="#aaaaaa">
<xsl:apply-templates/>
</tr>
</xsl:template>
<xsl:template match="n1:tr[position() mod 2 =1]">
<tr bgcolor="#aaaaff">
<xsl:apply-templates/>
</tr>
</xsl:template>
The simplest solution (taking your sample stylesheet as representative of your actual needs) is to only loop over the desired nodes in the first place. Like this:
<xsl:template match="/">
<table>
<tr>
<td>Name</td>
<td>ID</td>
</tr>
<xsl:for-each select="//Book[#ID < 10000 and #ID > 6000]">
<xsl:variable name="altColor">
<xsl:choose>
<xsl:when test="position() mod 2 = 0">#FFFFFF</xsl:when>
<xsl:otherwise>#D3DFEE</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<tr bgcolor="{$altColor}">
<td><xsl:value-of select="#name" /></td>
<td><xsl:value-of select="#ID" /></td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
In other words, instead of conditionally including nodes in the body of the for-each simply select only those nodes you need. By doing this, position() will be relative to the set that you're iterating and it will work as expected.
For example, this (simplified) input:
<r>
<Book ID="6200"/>
<Book ID="7100"/>
<Book/>
<Book/>
<Book ID="8000"/>
<Book/>
<Book ID="9001"/>
<Book ID="9002"/>
</r>
Produces the correct alternation:
<table>
<tr>
<td>Name</td>
<td>ID</td>
</tr>
<tr bgcolor="#D3DFEE">
<td />
<td>6200</td>
</tr>
<tr bgcolor="#FFFFFF">
<td />
<td>7100</td>
</tr>
<tr bgcolor="#D3DFEE">
<td />
<td>8000</td>
</tr>
<tr bgcolor="#FFFFFF">
<td />
<td>9001</td>
</tr>
<tr bgcolor="#D3DFEE">
<td />
<td>9002</td>
</tr>
</table>
one simple solution would be to remember last color used and than use opposing one
instead basing your choice on position() and also you should move choice inside test for row
here is pseudo code
currentColor = color1
for each
if ( id > 10000 and id < 6000 ) {
if ( currentColor == color1 )
currentColor= color2
else
currentColor = color1
showDataInColor(currentColor)
}

XSL only show 10 loops in the for-each

My XML has 100 AgentSales nodes I only want to show the first 10 so far I have
<xsl:for-each select="NewDataSet/AgentSales">
<tr>
<xsl:if test="(position() mod 2 = 1)">
<xsl:attribute name="bgcolor">#cccccc</xsl:attribute>
</xsl:if>
<td>
<span style="font:20px arial; font-weight:bold;">
<xsl:value-of select="AgentName"/>
</span>
</td>
<td>
<span style="font:20px arial; font-weight:bold;">
<xsl:value-of select="State"/>
</span>
</td>
<td>
<span style="font:20px arial; font-weight:bold;">
<xsl:value-of select="time"/>
</span>
</td>
</tr>
</xsl:for-each>
New to the site but when I use the code brackets not all of my code shows? at least not in the preview below.
Use:
<xsl:for-each select="NewDataSet/AgentSales[not(position() >10)]">
<!-- Process each node from the node-list -->
</xsl:for-each>
Even better:
<xsl:apply-templates select="NewDataSet/AgentSales[not(position() >10)]"/>
Try something like:
<xsl:for-each select="NewDataSet/AgentSales">
<xsl:if test="position() <= 10">
...
</xsl:if>
</xsl:for-each>