XSLT pivot data by date - xslt

I have some XML records that show sales by date. I need to pivot this information into a table that shows the sales for a week.
Here is the XML:
<?xml version="1.0"?>
-<data>
<report datetime="9/24/2013 10:27 AM"/>
<reportnumber displayas="Report Number">7</reportnumber>
<businessdate displayas="Business Date">08/19/2013 to 08/25/2013</businessdate>
<businesssiteids displayas="Store">NEBO Enchiladas</businesssiteids>
<colheaders>
-<colheader day7="08/25/2013" day7name="Sunday" day6="08/24/2013" day6name="Saturday" day5="08/23/2013" day5name="Friday" day4="08/22/2013" day4name="Thursday" day3="08/21/2013" day3name="Wednesday" day2="08/20/2013" day2name="Tuesday" day1="08/19/2013" day1name="Monday"/>
</colheaders>
<row ReportAmtDaily="0.000000" ListName="Closing Reading:" BusinessDate="2013-08-19T00:00:00" BusinessSiteId="40E9E40D-5E7E-4EB3-99C6-8013CD31480D" linenumber="1"/>
<row ReportAmtDaily="0.000000" ListName="Closing Reading:" BusinessDate="2013-08-21T00:00:00" BusinessSiteId="40E9E40D-5E7E-4EB3-99C6-8013CD31480D" linenumber="2"/>
<row ReportAmtDaily="0.000000" ListName="Closing Reading:" BusinessDate="2013-08-22T00:00:00" BusinessSiteId="40E9E40D-5E7E-4EB3-99C6-8013CD31480D" linenumber="3"/>
<row ReportAmtDaily="0.000000" ListName="Closing Reading:" BusinessDate="2013-08-23T00:00:00" BusinessSiteId="40E9E40D-5E7E-4EB3-99C6-8013CD31480D" linenumber="4"/>
<row ReportAmtDaily="0.000000" ListName=" - Opening Reading" BusinessDate="2013-08-19T00:00:00" BusinessSiteId="40E9E40D-5E7E-4EB3-99C6-8013CD31480D" linenumber="5"/>
<row ReportAmtDaily="0.000000" ListName=" - Opening Reading" BusinessDate="2013-08-21T00:00:00" BusinessSiteId="40E9E40D-5E7E-4EB3-99C6-8013CD31480D" linenumber="6"/>
<row ReportAmtDaily="0.000000" ListName=" - Opening Reading" BusinessDate="2013-08-22T00:00:00" BusinessSiteId="40E9E40D-5E7E-4EB3-99C6-8013CD31480D" linenumber="7"/>
<row ReportAmtDaily="0.000000" ListName=" - Opening Reading" BusinessDate="2013-08-23T00:00:00" BusinessSiteId="40E9E40D-5E7E-4EB3-99C6-8013CD31480D" linenumber="8"/>
<row ReportAmtDaily="3334.220000" ListName="Gross Sales:" BusinessDate="2013-08-19T00:00:00" BusinessSiteId="40E9E40D-5E7E-4EB3-99C6-8013CD31480D" linenumber="9"/>
<row ReportAmtDaily="4187.620000" ListName="Gross Sales:" BusinessDate="2013-08-21T00:00:00" BusinessSiteId="40E9E40D-5E7E-4EB3-99C6-8013CD31480D" linenumber="10"/>
<row ReportAmtDaily="572.190000" ListName="Gross Sales:" BusinessDate="2013-08-22T00:00:00" BusinessSiteId="40E9E40D-5E7E-4EB3-99C6-8013CD31480D" linenumber="11"/>
<row ReportAmtDaily="10856.970000" ListName="Gross Sales:" BusinessDate="2013-08-23T00:00:00" BusinessSiteId="40E9E40D-5E7E-4EB3-99C6-8013CD31480D" linenumber="12"/>
</data>
I want the output to look like this for each businesssiteid:
------------------08/19/2013 08/20/20/2013 08/21/2013 08/22/2013 08/23/2013 08/24/2013 08/25/2013
Closing Reading: 0 0 0 0 0 0 0
-Opening Reading 0 0 0 0 0 0 0
Gross Sales 3334.22 0 4187.62 572.19 10856.97 0 0
I tried using a key and a variable in my XSLT but nothing returns either way and I don't think it's right because I need a value based on the combination of BusinessDate,ListName and BusinessSiteId.
This template of the returns the data in an un-pivoted format. Can someone point me in the right direction please.
<xsl:template match="row">
<tr>
<td>
<div class="col1">
<xsl:value-of select="#ListName"/>
</div>
</td>
<td>
<div class="col2">
<xsl:value-of select="#ReportAmtDaily"/>
</div>
</td>
<td>
<div class="col3">
<xsl:value-of select="#ReportAmtDaily"/>
</div>
</td>
<td>
<div class="col4">
<xsl:value-of select="#ReportAmtDaily"/>
</div>
</td>
<td>
<div class="col5">
<xsl:value-of select="#ReportAmtDaily"/>
</div>
</td>
<td>
<div class="col6">
<xsl:value-of select="#ReportAmtDaily"/>
</div>
</td>
<td>
<div class="col7">
<xsl:value-of select="#ReportAmtDaily"/>
</div>
</td>
<td>
<div class="col8">
<xsl:value-of select="#ReportAmtDaily"/>
</div>
</td>
<td>
<div class="col9">
<!--<xsl:value-of select="#"/>-->
</div>
</td>
</tr>
<!--</xsl:if>-->
XSLT
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" exclude-result-prefixes="msxsl"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<user:data xmlns:user="user">
<datamodel name="Sales.SDR">
<editable value="false" />
<fields>ListName,ReportQtyDaily</fields>
<filters>
<filter field="ReportNumber" value="7" />
</filters>
<totals />
<sorting>
</sorting>
<grouping />
<parameters>
<parameter field="BusinessDate" prompt="true" />
<parameter field="BusinessSiteIds" prompt="true" />
</parameters>
<reportheader headerfile="netsales1.xslt"/>
</datamodel>
<version>1.0</version>
<reportdescription>Filtered by: ReportNumber Parameters:
BusinessDate,BusinessSiteIds Fields Displayed: Line
Text</reportdescription>
<orientation value="horizontal" />
</user:data>
<xsl:output method="html" />
<xsl:key name="kListName" match="/data/row/#ListName" use="."/>
<xsl:template match="data">
<html>
<head />
<style type="text/css">div.col1{width:2.00in;left}div.col2{width:1.00in;right}div.col3{width:1.00in;right}div.col4{width:1.00in;right}div.col5{width:1.00in;right}div.col6{width:1.00in;right}div.col7{width:1.00in;right}div.col8{width:1.00in;right}div.col9{width:1.00in;right}</style>
<body>
<table class="report_header">
<tr>
<td class="title">Weekly SDR</td>
</tr>
<tr>
<td>
<table>
<tr>
<td />
<td class="parameterlabel">Business Date:</td>
<td>
<xsl:value-of select="businessdate" />
</td>
</tr>
<tr>
<td />
<td class="parameterlabel">Store:</td>
<td>
<xsl:value-of select="businesssiteids" />
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td />
<td />
</tr>
<tr>
<td>
<table class="report_tabulardata">
<thead class="report_tabulardata">
<tr class="columnheader">
<xsl:apply-templates select="colheaders/colheader" />
</tr>
</thead>
</table>
</td>
</tr>
<tr>
<td>
<table class="report_tabulardata">
<xsl:apply-templates select="row" />
</table>
</td>
</tr>
</table>
</body>
</html>
...other templates remove to make it easier to read
<xsl:template match="row">
<!--<xsl:for-each select="row[#ListName]">
<xsl:variable name="desc" select="row[#ListName]"/>-->
<tr>
<td>
<div class="col1" align="left">
<xsl:value-of select="#ListName"/>
</div>
</td>
<!--<xsl:for-each select="//#region[generate-id(.)= generate-id(key('b',.)[1])]">
</xsl:for-each>-->
<td>
<div class="col2" align="right">
<xsl:value-of select="#ReportAmtDaily"/>
</div>
</td>
<td>
<div class="col3" align="right">
<xsl:value-of select="#ReportAmtDaily"/>
</div>
</td>
<td>
<div class="col4" align="right">
<xsl:value-of select="#ReportAmtDaily"/>
</div>
</td>
<td>
<div class="col5" align="right">
<xsl:value-of select="#ReportAmtDaily"/>
</div>
</td>
<td>
<div class="col6" align="right">
<xsl:value-of select="#ReportAmtDaily"/>
</div>
</td>
<td>
<div class="col7" align="right">
<xsl:value-of select="#ReportAmtDaily"/>
</div>
</td>
<td>
<div class="col8" align="right">
<xsl:value-of select="#ReportAmtDaily"/>
</div>
</td>
<td>
<div class="col9" align="right">
<!--<xsl:value-of select="sum($thisGroup/#ReportAmtDaily)"/>-->
</div>
</td>
</tr>
<!--</xsl:for-each>-->
</xsl:template>
</xsl:stylesheet>

Something like this might do the trick:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:variable
select="reverse(/data/colheaders/colheader/#*[not(local-name()[contains(.,'name')])])"
name="days"/>
<xsl:variable name="ids" select="distinct-values((//#BusinessSiteId))"/>
<xsl:template match="/">
<html>
<body>
<h2>Weekly Report</h2>
<p>Report date/time: <xsl:value-of select="/data/report/#datetime"/></p>
<p><xsl:value-of select="/data/reportnumber/#displayas"/>: <xsl:value-of
select="/data/reportnumber"/></p>
<p><xsl:value-of select="/data/businessdate/#displayas"/>: <xsl:value-of
select="/data/businessdate"/></p>
<p><xsl:value-of select="/data/businesssiteids/#displayas"/>: <xsl:value-of
select="/data/businesssiteids"/></p>
<xsl:for-each select="$ids">
<h4>Site ID: <xsl:value-of select="."/></h4>
<table>
<thead>
<tr>
<th/>
<xsl:apply-templates select="$days" mode="header"/>
</tr>
</thead>
<tbody>
<tr>
<td>Closing Reading:</td>
<xsl:apply-templates select="$days" mode="closing">
<xsl:with-param name="currentid" select="."/>
</xsl:apply-templates>
</tr>
<tr>
<td>Opening Reading:</td>
<xsl:apply-templates select="$days" mode="opening">
<xsl:with-param name="currentid" select="."/>
</xsl:apply-templates>
</tr>
<tr>
<td>Gross Sales:</td>
<xsl:apply-templates select="$days" mode="sales">
<xsl:with-param name="currentid" select="."/>
</xsl:apply-templates>
</tr>
</tbody>
</table>
</xsl:for-each>
</body>
</html>
</xsl:template>
<xsl:template match="/data/colheaders/colheader/#*" mode="header">
<th>
<xsl:value-of select="."/>
</th>
</xsl:template>
<xsl:template match="/data/colheaders/colheader/#*" mode="closing">
<xsl:param name="currentid"/>
<xsl:variable
select="concat(substring-after(substring-after(.,'/'),'/') , '-', substring-before(.,'/'), '-', substring-before(substring-after(.,'/'),'/'))"
name="closedate"/>
<xsl:for-each select=".">
<xsl:choose>
<xsl:when
test="/data/row/#BusinessDate[../#BusinessSiteId=$currentid][../#ListName='Closing Reading:'][contains(.,$closedate)]">
<xsl:variable name="numbera" select="/data/row/#BusinessDate[../#BusinessSiteId=$currentid][../#ListName='Closing Reading:'][contains(.,$closedate)]/../#ReportAmtDaily"/>
<td>
<xsl:value-of
select="format-number( round(100*$numbera) div 100 ,
'###,###,##0.00' )"
/>
</td>
</xsl:when>
<xsl:otherwise>
<td>
<xsl:text>0</xsl:text>
</td>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
<xsl:template match="/data/colheaders/colheader/#*" mode="opening">
<xsl:param name="currentid"/>
<xsl:variable
select="concat(substring-after(substring-after(.,'/'),'/') , '-', substring-before(.,'/'), '-', substring-before(substring-after(.,'/'),'/'))"
name="opendate"/>
<xsl:for-each select=".">
<xsl:choose>
<xsl:when
test="/data/row/#BusinessDate[../#BusinessSiteId=$currentid][../#ListName=' - Opening Reading'][contains(.,$opendate)]">
<xsl:variable name="numberb" select="/data/row/#BusinessDate[../#BusinessSiteId=$currentid][../#ListName=' - Opening Reading'][contains(.,$opendate)]/../#ReportAmtDaily"/>
<td>
<xsl:value-of
select="format-number( round(100*$numberb) div 100 ,
'###,###,##0.00' )"
/>
</td>
</xsl:when>
<xsl:otherwise>
<td>
<xsl:text>0</xsl:text>
</td>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
<xsl:template match="/data/colheaders/colheader/#*" mode="sales">
<xsl:param name="currentid"/>
<xsl:variable
select="concat(substring-after(substring-after(.,'/'),'/') , '-', substring-before(.,'/'), '-', substring-before(substring-after(.,'/'),'/'))"
name="salesdate"/>
<xsl:for-each select=".">
<xsl:choose>
<xsl:when
test="/data/row/#BusinessDate[../#BusinessSiteId=$currentid][../#ListName='Gross Sales:'][contains(.,$salesdate)]">
<xsl:variable name="numberc" select="/data/row/#BusinessDate[../#BusinessSiteId=$currentid][../#ListName='Gross Sales:'][contains(.,$salesdate)]/../#ReportAmtDaily"/>
<td>
<xsl:value-of
select="format-number( round(100*$numberc) div 100 ,
'###,###,##0.00' )"
/>
</td>
</xsl:when>
<xsl:otherwise>
<td>
<xsl:text>0</xsl:text>
</td>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>

Related

XSLT substring-after last separator [duplicate]

I Have a Attribute that I want to display, but I only want to display the last portion of it indicated by an "-". I am using substring-after to do this but this only works if there is one charactor. There are occasions where there might be one and some where there is two. I have seen some recursive templates for this but I have not seen them in a For-each Loop like I have it here and I am not sure where I would put everything in my XSL document.
Here is my XML document:
<?xml version="1.0" encoding="UTF-8"?>
<JobList>
<Job T.number="28" />
<Job T.identifier="10mm Drill" />
<Job oper.jobName="2: T28-Contour Milling - Grind me back" />
<Job T.number="3" />
<Job T.identifier="9mm Drill" />
<Job oper.jobName="3: T3 Contour Milling" />
</JobList>
Here is my XSL Document. I am using XSL 1.0. The result I am looking for is I want this to be displayed as "10mm Drill - Grind me back" not "10mm Drill-Contour Milling - Grind me back" which is what I am getting now using the substring-after function or something with the same result.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" encoding="UTF-8" method="xml" />
<xsl:param name="REPORT">joblist</xsl:param>
<xsl:param name="LOCALE">en-GB</xsl:param>
<xsl:param name="FORMAT">html</xsl:param>
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<title>Tool Report</title>
</head>
<body>
<xsl:apply-templates />
</body>
</html>
</xsl:template>
<xsl:template match="JobList">
<div style="font-size:;">
<table width="100%" style="margin-bottom:50px;font:bold 10px arial;">
<thead>
<tr>
<th style="text-align:center;font-family:Arial;font-size:13;font:bold 7px arial;">
<xsl:value-of select="#month">
</xsl:value-of>
<span>.</span>
<xsl:value-of select="#day">
</xsl:value-of>
<span>.</span>
<xsl:value-of select="#year">
</xsl:value-of>
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center;font:normal 7px arial;font-size:12px;">
<xsl:value-of select="//Job[position()=1]/#cfg.JOBLISTNAME" />
<span>
</span>
<span>
</span>
</td>
</tr>
</tbody>
<table width="100%" border="1" style="margin-bottom:50px;font:13px arial;">
<thead style="font:19;">
<tr style="font-size:19;">
<td style="text-align:center;font-weight:bold;font-size:19;">
</td>
<td style="text-align:center;font-weight:bold;font-size:19;">
</td>
<td style="text-align:center;font-weight:bold;font-size:19;">
</td>
<td style="text-align:center;font-weight:bold;font-size:19;">
</td>
<td style="text-align:center;font-weight:bold;font-size:19;">
</td>
<td style="text-align:center;font-weight:bold;font-size:19;">
</td>
<td style="text-align:center;font-weight:bold;font-size:19;">
</td>
<td style="text-align:center;font-weight:bold;font-size:19;">
</td>
<td style="text-align:center;font-weight:bold;font-size:19;">
</td>
</tr>
</thead>
<tbody style="font-size:19;">
<xsl:for-each select="//Job[not(#T.number=preceding::Job/#T.number)]">
<tr style="font-size:19;">
<td style="font-size:19;">
<xsl:value-of select="#T.number" />
</td>
<td>
</td>
<td style="font-size:19;">
<xsl:value-of select="#T.identifier" />
<xsl:choose>
<xsl:when test="contains(#T.toolComment3, 'GRIND') or contains(#T.toolComment3, 'Grind')">
<xsl:value-of select="#T.toolComment3" />
</xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="contains(#T.comment2, 'GRIND') or contains(#T.comment2, 'Grind')">
<xsl:value-of select="#T.comment2" />
</xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="contains(#oper.jobName, 'GRIND') or contains(#oper.jobName, 'Grind')">
<xsl:value-of select="substring-after(#oper.jobName, '-')" />
</xsl:when>
</xsl:choose>
</td>
</tr>
</xsl:for-each>
</tbody>
</table>
</table>
</div>
</xsl:template>
</xsl:stylesheet>
Use a named recursive template to get the last token of the text string.
<xsl:template name="last-token">
<xsl:param name="text"/>
<xsl:param name="delimiter" select="'-'"/>
<xsl:choose>
<xsl:when test="contains($text, $delimiter)">
<!-- recursive call -->
<xsl:call-template name="last-token">
<xsl:with-param name="text" select="substring-after($text, $delimiter)"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Example of call: http://xsltransform.net/bFWR5Ew

XSLT variable not working

I have the following piece of XSLT code:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml">
<xsl:variable name="condition">(coasts='Adriatic Sea')or(coasts='Mediterranean Sea')</xsl:variable>
<xsl:template match="cia">
<html>
<head></head>
<body>
<table border="1">
<tr>
<th>Country</th>
<th>Capital</th>
<th>Area</th>
<th>Population</th>
<th>Inflation rate</th>
</tr>
<xsl:for-each select="country">
<xsl:if test="{$condition}">
<tr>
<td>
<xsl:value-of select="#name"/>
</td>
<td>
<xsl:value-of select="#capital"/>
</td>
<td>
<xsl:value-of select="#total_area"/>
</td>
<td>
<xsl:value-of select="#population"/>
</td>
<td>
<xsl:value-of select="#inflation"/>
</td>
</tr>
</xsl:if>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
If put the conditional expression directly in the if element the code works fine, however, my problem is that when I assign the same conditional expression to the variable and then reference it in the if element it doesn't work. Am I doing something wrong? Is this possible?
Thanks!
There are multiple problems:
The brackets in <xsl:if test="{$condition}"> are unnecessary; use <xsl:if test="$condition">
Use the following xsl:variable construct:
<xsl:variable name="condition"
select="(coasts='Adriatic Sea')or(coasts='Mediterranean Sea')"/>
When you had the condition in your xsl:if the test was performed relative to each country. This is not the case in a top-level variable. The value of the variable is the result of the expression, not the expression itself. If you insist on a variable, then initialize it inside the loop.
See the following stylesheet:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml">
<xsl:template match="cia">
<html>
<head></head>
<body>
<table border="1">
<tr>
<th>Country</th>
<th>Capital</th>
<th>Area</th>
<th>Population</th>
<th>Inflation rate</th>
</tr>
<xsl:for-each select="country">
<xsl:variable name="condition"
select="(coasts='Adriatic Sea') or
(coasts='Mediterranean Sea')" />
<xsl:if test="$condition">
<tr>
<td>
<xsl:value-of select="#name" />
</td>
<td>
<xsl:value-of select="#capital" />
</td>
<td>
<xsl:value-of select="#total_area" />
</td>
<td>
<xsl:value-of select="#population" />
</td>
<td>
<xsl:value-of select="#inflation" />
</td>
</tr>
</xsl:if>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Input:
<cia>
<country name="test1" inflation="22">
<coasts>Adriatic Sea</coasts>
</country>
<country name="test2" inflation="7">
<coasts>No match</coasts>
</country>
</cia>
Output (only the first country passes the test):
<html xmlns="http://www.w3.org/1999/xhtml">
<head></head>
<body>
<table border="1">
<tr>
<th>Country</th>
<th>Capital</th>
<th>Area</th>
<th>Population</th>
<th>Inflation rate</th>
</tr>
<tr>
<td>test1</td>
<td></td>
<td></td>
<td></td>
<td>22</td>
</tr>
</table>
</body>
</html>
Note that you don't really even need a separate condition; it's better to select just the desired elements in the first place. This loop produces the same output:
<xsl:for-each
select="country[(coasts='Adriatic Sea') or
coasts='Mediterranean Sea')]">
<tr>
<td>
<xsl:value-of select="#name" />
</td>
<td>
<xsl:value-of select="#capital" />
</td>
<td>
<xsl:value-of select="#total_area" />
</td>
<td>
<xsl:value-of select="#population" />
</td>
<td>
<xsl:value-of select="#inflation" />
</td>
</tr>
</xsl:for-each>
Replace:
<xsl:for-each select="country">
with
<xsl:apply templates select="country"/>
also, add these templates:
<xsl:template match="country"/>
<xsl:template match=
"country[coasts='Adriatic Sea'
or
coasts='Mediterranean Sea'
]">
<xsl:template match=
"country[coasts='Adriatic Sea'
or
coasts='Mediterranean Sea'
]">
<tr>
<td>
<xsl:value-of select="#name"/>
</td>
<td>
<xsl:value-of select="#capital"/>
</td>
<td>
<xsl:value-of select="#total_area"/>
</td>
<td>
<xsl:value-of select="#population"/>
</td>
<td>
<xsl:value-of select="#inflation"/>
</td>
</tr>
</xsl:template>
Did you note that the <xsl:if> "magically" disappeared?
Of course, this code can be improved even further, but you haven't provided neither an instance of the XML document on which the transformation is to be applied, nor the desired output.

using urn:helper in xsl

I'm new to xslt. I tried using urn:helper in the stylesheet tag. But it throws the following error.
"Cannot find the script or external object that implements prefix 'urn:Helper'".
Below is the snippet used in my code.
xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:myObj="urn:Helper"
xmlns:t="http://microsoft.com/schemas/VisualStudio/TeamTest/2006"
Am I missing something?
Thanks..
edit: complete stylesheet
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:myObj="urn:Helper"
xmlns:t="http://microsoft.com/schemas/VisualStudio/TeamTest/2006">
<xsl:param name="today"></xsl:param>
<xsl:param name="results"></xsl:param>
<xsl:param name="pass" select="'Passed'"/>
<xsl:param name="fail" select="'Failed'"/>
<xsl:key name="class-key" match="#className" use="."/>
<xsl:variable name="unique-classes" select="//t:TestMethod/#className[generate-id(.) =generate-id(key('class-key',.))]" />
<xsl:template match="/">
<html>
<body style="font-family:Verdana; font-size:10pt">
<h1>Test Results Summary</h1>
<table style="font-family:Verdana; font-size:10pt">
<tr>
<td>
<b>Run Date/Time</b>
</td>
<td>
</td>
</tr>
<tr>
<td>
Start Time:
</td>
<td>
<xsl:value-of select="myObj:DateTimeToString(//t:TestRun/t:Times/#start)"/>
</td>
</tr>
<tr>
<td>
End Time:
</td>
<td>
<xsl:value-of select="myObj:DateTimeToString(//t:TestRun/t:Times/#finish)"/>
</td>
</tr>
<tr>
<td>
Duration:
</td>
<td>
<xsl:value-of select="myObj:TimeSpan(//t:TestRun/t:Times/#start,//t:TestRun/t:Times/#finish)"/>
</td>
</tr>
<tr>
<td>
<b>Results File</b>
</td>
<td>
<xsl:value-of select="$results"/>
</td>
</tr>
</table>
Coverage Summary
<xsl:call-template name="summary" />
<!--<xsl:call-template name="details" />-->
<xsl:call-template name="details2" />
</body>
</html>
</xsl:template>
<xsl:template name="summary">
<h3>Test Summary</h3>
<table style="width:640;border:1px solid black;font-family:Verdana; font-size:10pt">
<tr>
<td style="font-weight:bold">Total</td>
<td style="font-weight:bold">Failed</td>
<td style="font-weight:bold">Passed</td>
<td style="font-weight:bold">Inconclusive</td>
</tr>
<tr>
<td >
<xsl:value-of select="/t:TestRun/t:ResultSummary/t:Counters/#total"/>
</td>
<td style="background-color:pink;">
<xsl:value-of select="/t:TestRun/t:ResultSummary/t:Counters/#failed"/>
</td>
<td style="background-color:lightgreen;">
<xsl:value-of select="/t:TestRun/t:ResultSummary/t:Counters/#passed"/>
</td>
<td style="background-color:yellow;">
<xsl:value-of select="/t:TestRun/t:ResultSummary/t:Counters/#inconclusive"/>
</td>
</tr>
</table>
</xsl:template>
<xsl:template name="details">
<h3>Unit Test Results</h3>
<table style="width:640;border:1px solid black;font-family:Verdana; font-size:10pt;">
<tr>
<td style="font-weight:bold">Test Name</td>
<td style="font-weight:bold">Result</td>
<td style="font-weight:bold">Duration</td>
</tr>
<xsl:for-each select="/t:TestRun/t:Results/t:UnitTestResult">
<xsl:sort select="#testName"/>
<tr>
<xsl:attribute name="style">
<xsl:choose>
<xsl:when test="#outcome='Failed'">background-color:pink;</xsl:when>
<xsl:when test="#outcome='Passed'">background-color:lightgreen;</xsl:when>
<xsl:otherwise>background-color:yellow;</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<td>
<xsl:value-of select="#testName"/>
</td>
<td>
<xsl:choose>
<xsl:when test="#outcome='Failed'">FAILED</xsl:when>
<xsl:when test="#outcome='Passed'">Passed</xsl:when>
<xsl:otherwise>Inconclusive</xsl:otherwise>
</xsl:choose>
</td>
<td>
<xsl:value-of select="#duration"/>
</td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
<xsl:template name="details2">
<h3>Unit Test Results</h3>
<table border="0" style="width:640;border:1px solid black;font-family:Verdana; font-size:10pt;">
<xsl:for-each select="$unique-classes">
<xsl:sort />
<xsl:variable name="curClass" select="."/>
<xsl:variable name="return" select="myObj:GetClassInformation($curClass)"/>
<!--<xsl:for-each select="//TestRun/tests/value/testMethod[className=$curClass]">-->
<tr>
<td valign="bottom" style="background-color:beige;font-weight:bold;" colspan="3">
<font>
<xsl:value-of select="concat('',$return/className)"/>
</font>
</td>
</tr>
<tr>
<td style="font-weight:bold">Test Name</td>
<td style="font-weight:bold">Result</td>
<td style="font-weight:bold">Duration</td>
</tr>
<xsl:for-each select="//t:UnitTest/t:TestMethod[#className=$curClass]">
<xsl:sort select="#name"/>
<xsl:variable name="testid" select="../#id"/>
<xsl:for-each select="//t:UnitTestResult[#testId=$testid]">
<xsl:call-template name="classRunsDetail">
<xsl:with-param name="testid" select="."/>
</xsl:call-template>
</xsl:for-each>
</xsl:for-each>
<tr>
<td style="border-bottom:0px solid black;height:1px;background-color:black" colspan="3"></td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
<xsl:template name="classRunsDetail">
<xsl:param name="testid"/>
<tr>
<xsl:attribute name="style">
<xsl:choose>
<xsl:when test="#outcome = $fail">background-color:pink;</xsl:when>
<xsl:when test="#outcome = $pass">background-color:lightgreen;</xsl:when>
<xsl:otherwise>background-color:yellow;</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<td>
<xsl:value-of select="#testName"/>
</td>
<td>
<xsl:choose>
<xsl:when test="#outcome = $fail">FAILED</xsl:when>
<xsl:when test="#outcome = $pass">Passed</xsl:when>
<xsl:otherwise>Inconclusive</xsl:otherwise>
</xsl:choose>
</td>
<td>
<xsl:value-of select="#duration"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
There is no problem with your xsl:stylesheet element.
The problem is here:
<xsl:value-of select="myObj:DateTimeToString(//t:TestRun/t:Times/#start)"/>
From http://www.w3.org/TR/xslt#section-Extension-Functions
If a FunctionName in a FunctionCall
expression is not an NCName (i.e. if
it contains a colon), then it is
treated as a call to an extension
function. The FunctionName is expanded
to a name using the namespace
declarations from the evaluation
context.
If the XSLT processor does not have an
implementation of an extension
function of a particular name
available, then the function-available
function must return false for that
name. If such an extension function
occurs in an expression and the
extension function is actually called,
the XSLT processor must signal an
error.
The answer: You are missing the extension function implementation.
So, you must provide details of your processor and re-ask what is the specific way that your processor is linked to the implementation of extended functions.
I see you grabbed that little helper object from this post. It seems right, but make sure you are using the C# code to actually do the transform.

Using keys in xslt for converting trx file of mstest

I have written an xsl for converting the trx file of mstest into html.
Following from this link, I'm unable to get the class names and number of passes and failures for each class to be printed in the output.
I'm not sure where I'm goin wrong. the style sheet is applied on the same input file in the link.
Thanks.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:t="http://microsoft.com/schemas/VisualStudio/TeamTest/2006">
<xsl:param name="today"></xsl:param>
<xsl:param name="results"></xsl:param>
<xsl:param name="pass" select="'Passed'"/>
<xsl:param name="fail" select="'Failed'"/>
<xsl:param name="incon" select="'Inconclusive'"/>
<xsl:param name="error" select="'Error'"/>
<xsl:key name="class-key" match="#className" use="."/>
<xsl:variable name="unique-classes" select="//t:TestMethod/#className[generate-id(.)=generate-id(key('class-key',.))]" />
<xsl:template match="/">
<html>
<head>
<script type="text/javascript">
//Some javascript code
</script>
</head>
<body style="font-family:Verdana; font-size:10pt">
Coverage Summary
<xsl:call-template name="summary" />
<xsl:call-template name="details2" />
</body>
</html>
</xsl:template>
<xsl:template name="summary">
<h3>Test Summary</h3></code>
<table style="width:640;border:1px solid black;font-family:Verdana; font-size:10pt">
<tr>
<td style="font-weight:bold;">Total</td>
<td style="font-weight:bold;">Failed</td>
<td style="font-weight:bold;">Passed</td>
<td style="font-weight:bold;">Inconclusive</td>
<td style="font-weight:bold;">Error</td>
</tr>
<tr>
<td >
<xsl:value-of select="/t:TestRun/t:ResultSummary/t:Counters/#total"/>
</td>
<td style="background-color:pink;">
<xsl:value-of select="/t:TestRun/t:ResultSummary/t:Counters/#failed"/>
</td>
<td style="background-color:lightgreen;">
<xsl:value-of select="/t:TestRun/t:ResultSummary/t:Counters/#passed"/>
</td>
<td style="background-color:lightblue;">
<xsl:value-of select="/t:TestRun/t:ResultSummary/t:Counters/#inconclusive"/>
</td>
<td style="background-color:yellow;">
<xsl:value-of select="/t:TestRun/t:ResultSummary/t:Counters/#error"/>
</td>
</tr>
</table>
</xsl:template>
<xsl:template name="details2">
<h3>Unit Test Results</h3>
<table border="0" style="width:640;border:1px solid black;font-family:Verdana; font-size:10pt;">
<tr>
<td></td>
<td id="data" style="font-weight:bold;">Test Name</td>
<td id="data" style="font-weight:bold;">Result</td>
<td id="data" style="font-weight:bold;">Duration</td>
</tr>
<xsl:for-each select="$unique-classes">
<xsl:sort />
<xsl:variable name="curClass" select="."/>
<xsl:variable name="parentId" select="generate-id(./..)" />
<xsl:variable name="currentId" select="generate-id(.)" />
<tr id="{$parentId}">
<td id="{$currentId}"
style="font-weight:bold; cursor:pointer;"
onClick="toggleDetail(this)">[+]</td>
<xsl:sort select="#name"/>
<xsl:variable name="testid" select="../#id"/>
<xsl:with-param name="testid" select="."/>
<xsl:with-param name="curClass" select="."/>
<xsl:call-template name="groups" />
</tr>
<xsl:call-template name="classRunsDetail">
<xsl:with-param name="curClass" select="."/>
</xsl:call-template>
<tr id="{$currentId}-end" style="display:none;">
<td style="border-bottom:0px solid black;height:1px;background-color:black" colspan="4"></td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
<xsl:template name="classRunsDetail">
<xsl:param name="curClass"/>
<xsl:variable name="parentId" select="generate-id(.)" />
<xsl:for-each select="//t:UnitTest/t:TestMethod[#className=$curClass]">
<xsl:sort select="#name"/>
<xsl:variable name="testid" select="../#id"/>
<xsl:for-each select="//t:UnitTestResult[#testId=$testid]">
<tr id="{$parentId}">
<xsl:attribute name="style">
<xsl:choose>
<xsl:when test="#outcome = $fail">background-color:pink;</xsl:when>
<xsl:when test="#outcome = $pass">background-color:lightgreen;</xsl:when>
<xsl:when test="#outcome = $incon">background-color:lightblue;</xsl:when>
<xsl:otherwise>background-color:yellow;</xsl:otherwise>
</xsl:choose>
display:none;
</xsl:attribute>
<td></td>
<td id="data">
<xsl:value-of select="#testName"/>
</td>
<td id="data">
<xsl:choose>
<xsl:when test="#outcome = $fail">FAILED</xsl:when>
<xsl:when test="#outcome = $pass">Passed</xsl:when>
<xsl:when test="#outcome = $incon">Not Run</xsl:when>
<xsl:otherwise>Error</xsl:otherwise>
</xsl:choose>
</td>
<td id="data">
<xsl:value-of select="#duration"/>
</td>
</tr>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
<xsl:key name="class" match="t:TestMethod" use="#className"/>
<xsl:key name="result" match="t:UnitTestResult" use="#testName"/>
<xsl:template name="groups" match="t:TestMethod[count(.|key('class',#className)[1])=1]">
<xsl:variable name="result" select="key('result',key('class',#className)/#name)"/>
<td valign="bottom" style="background-color:beige;font-weight:bold;" colspan="3">
<xsl:value-of select="#className"/>
</td>
<td>
<xsl:value-of select="count($result[#outcome='Passed'])"/>
</td>
<td>
<xsl:value-of select="count($result[#outcome='Failed'])"/>
</td>
<td>
<xsl:value-of select="count($result[#outcome='Inconclusive'])"/>
</td>
</xsl:template>
</xsl:stylesheet>
I was using XSL for the same thing, but it was a nightmare to analyze trx.
trx2html.codeplex.com Latest version, is based on LINQ2XML !!
The provided stylesheet didn't even run...
I'm just guessing here, because there is no desired output.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:t="http://microsoft.com/schemas/VisualStudio/TeamTest/2006">
<xsl:param name="pass" select="'Passed'"/>
<xsl:param name="fail" select="'Failed'"/>
<xsl:param name="incon" select="'Inconclusive'"/>
<xsl:param name="error" select="'Error'"/>
<xsl:key name="class" match="t:TestMethod" use="#className"/>
<xsl:key name="result" match="t:UnitTestResult" use="#testName"/>
<xsl:template match="text()"/>
<xsl:template match="/*">
<html>
<head>
<script type="text/javascript">
//Some javascript code
</script>
</head>
<body style="font-family:Verdana; font-size:10pt">
Coverage Summary
<xsl:apply-templates select="t:ResultSummary|t:TestDefinitions"/>
</body>
</html>
</xsl:template>
<xsl:template match="t:Counters">
<h3>Test Summary</h3>
<table style="width:640;border:1px solid black;font-family:Verdana; font-size:10pt">
<tr>
<td style="font-weight:bold;">Total</td>
<td style="font-weight:bold;">Failed</td>
<td style="font-weight:bold;">Passed</td>
<td style="font-weight:bold;">Inconclusive</td>
<td style="font-weight:bold;">Error</td>
</tr>
<tr>
<td >
<xsl:value-of select="#total"/>
</td>
<td style="background-color:pink;">
<xsl:value-of select="#failed"/>
</td>
<td style="background-color:lightgreen;">
<xsl:value-of select="#passed"/>
</td>
<td style="background-color:lightblue;">
<xsl:value-of select="#inconclusive"/>
</td>
<td style="background-color:yellow;">
<xsl:value-of select="#error"/>
</td>
</tr>
</table>
</xsl:template>
<xsl:template match="t:TestDefinitions">
<h3>Unit Test Results</h3>
<table border="0" style="width:640;border:1px solid black;font-family:Verdana; font-size:10pt;">
<tr>
<td></td>
<td id="data" style="font-weight:bold;">Test Name</td>
<td id="data" style="font-weight:bold;">Result</td>
<td id="data" style="font-weight:bold;">Duration</td>
</tr>
<xsl:apply-templates/>
</table>
</xsl:template>
<xsl:template match="t:TestMethod[count(.|key('class',#className)[1])=1]">
<xsl:variable name="result" select="key('result',key('class',#className)/#name)"/>
<tr id="{generate-id(.)}">
<td id="{generate-id(#className)}"
style="font-weight:bold; cursor:pointer;"
onClick="toggleDetail(this)">[+]</td>
<td valign="bottom" style="background-color:beige;font-weight:bold;" colspan="3">
<xsl:value-of select="#className"/>
</td>
<td>
<xsl:value-of select="count($result[#outcome='Passed'])"/>
</td>
<td>
<xsl:value-of select="count($result[#outcome='Failed'])"/>
</td>
<td>
<xsl:value-of select="count($result[#outcome='Inconclusive'])"/>
</td>
</tr>
<xsl:apply-templates select="$result">
<xsl:sort select="#name"/>
<xsl:with-param name="id" select="generate-id(#className)"/>
</xsl:apply-templates>
<tr id="{generate-id(.)}-end" style="display:none;">
<td style="border-bottom:0px solid black;height:1px;background-color:black" colspan="4"></td>
</tr>
</xsl:template>
<xsl:template match="t:UnitTestResult">
<xsl:param name="id"/>
<tr id="{$id}">
<xsl:attribute name="style">
<xsl:choose>
<xsl:when test="#outcome = $fail">background-color:pink;</xsl:when>
<xsl:when test="#outcome = $pass">background-color:lightgreen;</xsl:when>
<xsl:when test="#outcome = $incon">background-color:lightblue;</xsl:when>
<xsl:otherwise>background-color:yellow;</xsl:otherwise>
</xsl:choose>
<xsl:text>display:none;</xsl:text>
</xsl:attribute>
<td></td>
<td id="data">
<xsl:value-of select="#testName"/>
</td>
<td id="data">
<xsl:choose>
<xsl:when test="#outcome = $fail">FAILED</xsl:when>
<xsl:when test="#outcome = $pass">Passed</xsl:when>
<xsl:when test="#outcome = $incon">Not Run</xsl:when>
<xsl:otherwise>Error</xsl:otherwise>
</xsl:choose>
</td>
<td id="data">
<xsl:value-of select="#duration"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
Note: I've reversed your logic. Don't drive the transformation with for-each instructions. Apply templates to descendants, instead.

Xslt transformation for-each

Could anyone help me with the following transformation?
Here is the XML
<Chart>
<Chart.Series>
<DataSeries LegendText="Complete On Time" >
<DataSeries.DataPoints>
<DataPoint AxisXLabel="Sep 09" YValue="10" />
<DataPoint AxisXLabel="Oct 09" YValue="11" />
<DataPoint AxisXLabel="Nov 09" YValue="12" />
</DataSeries.DataPoints>
</DataSeries>
<DataSeries LegendText="Complete Overdue" >
<DataSeries.DataPoints>
<DataPoint YValue="1" />
<DataPoint YValue="2" />
<DataPoint YValue="3" />
</DataSeries.DataPoints>
</DataSeries>
</Chart.Series>
</Chart>
and here is the output id like
<table>
<thead>
<tr>
<th></th>
<th>Complete On Time</th>
<th>Complete Overdue</th>
</tr>
</thead>
<tbody>
<tr>
<th>Sep 09</th>
<th>10</th>
<th>1</th>
</tr>
<tr>
<th>Oct 09</th>
<th>11</th>
<th>2</th>
</tr>
<tr>
<th>Nov 09</th>
<th>12</th>
<th>3</th>
</tr>
</tbody>
A more natural solution:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<!-- basic table structure -->
<xsl:template match="Chart">
<table>
<thead>
<xsl:apply-templates select="Chart.Series" mode="thead" />
</thead>
<tbody>
<xsl:apply-templates select="Chart.Series" mode="tbody" />
</tbody>
</table>
</xsl:template>
<!-- table head -->
<xsl:template match="Chart.Series" mode="thead">
<tr>
<th />
<xsl:for-each select="DataSeries">
<th>
<xsl:value-of select="#LegendText" />
</th>
</xsl:for-each>
</tr>
</xsl:template>
<!-- table body -->
<xsl:template match="Chart.Series" mode="tbody">
<xsl:variable name="ds" select="DataSeries" />
<!-- the first data series contains the labels -->
<xsl:for-each select="$ds[1]/*/DataPoint">
<xsl:variable name="pos" select="position()" />
<tr>
<td>
<xsl:value-of select="#AxisXLabel" />
</td>
<!-- process all data points at the current position -->
<xsl:apply-templates select="$ds/*/DataPoint[$pos]" />
</tr>
</xsl:for-each>
</xsl:template>
<!-- data points become a <td> -->
<xsl:template match="DataPoint">
<td>
<xsl:value-of select="#YValue" />
</td>
</xsl:template>
</xsl:stylesheet>
Note that I use template modes to do different things with the same input.
The result is:
<table>
<thead>
<tr>
<th />
<th>Complete On Time</th>
<th>Complete Overdue</th>
</tr>
</thead>
<tbody>
<tr>
<td>Sep 09</td>
<td>10</td>
<td>1</td>
</tr>
<tr>
<td>Oct 09</td>
<td>11</td>
<td>2</td>
</tr>
<tr>
<td>Nov 09</td>
<td>12</td>
<td>3</td>
</tr>
</tbody>
</table>
This is something close. It's been a couple of year for me though that I've done XSLT - ignore bad style.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output indent="yes" omit-xml-declaration="yes" ></xsl:output>
<xsl:template match="/">
<table>
<thead>
<tr>
<th></th>
<xsl:apply-templates select=".//DataSeries" />
</tr>
</thead>
<tbody>
<xsl:apply-templates select="//DataSeries[1]//DataPoint">
<xsl:with-param name="datablock">1</xsl:with-param>
</xsl:apply-templates>
</tbody>
</table>
</xsl:template>
<xsl:template match="DataSeries">
<th>
<xsl:value-of select="#LegendText"></xsl:value-of>
</th>
</xsl:template>
<xsl:template match="DataPoint">
<xsl:param name="datablock" />
<xsl:variable name="posi" select="position()"></xsl:variable>
<xsl:if test="$datablock = 1">
<tr>
<xsl:for-each select="#*">
<th>
<xsl:value-of select="."></xsl:value-of>
</th>
</xsl:for-each>
<xsl:apply-templates select="//DataSeries[$datablock+1]//DataPoint[$posi]">
<xsl:with-param name="datablock" select="$datablock + 1">
</xsl:with-param>
</xsl:apply-templates>
</tr>
</xsl:if>
<xsl:if test="$datablock != 1">
<xsl:for-each select="#*">
<th>
<xsl:value-of select="."></xsl:value-of>
</th>
</xsl:for-each>
<xsl:apply-templates select="//DataSeries[$datablock+1]//DataPoint[$posi]">
<xsl:with-param name="datablock" select="$datablock + 1">
</xsl:with-param>
</xsl:apply-templates>
</xsl:if>
</xsl:template>