I will be having xml as below:
<catalog>
<performanceVO>
<fAnReVal>
<fNumber>402</fNumber>
<rtnDate alt="12/31/1998">1998-12-31</rtnDate>
<rtnWOSC alt="10.73">10.73</rtnWOSC>
<rtnWSC alt="4.35">4.35</rtnWSC>
</fAnReVal>
<fAnReVal>
<fNumber>402</fNumber>
<rtnDate alt="12/31/1999">1999-12-31</rtnDate>
<rtnWOSC alt="97.91">97.91</rtnWOSC>
<rtnWSC alt="86.54">86.54</rtnWSC>
</fAnReVal>
<fAnReVal>
<fNumber>402</fNumber>
<rtnDate alt="12/31/2000">2000-12-31</rtnDate>
<rtnWOSC alt="46.58">46.58</rtnWOSC>
<rtnWSC alt="38.15">38.15</rtnWSC>
</fAnReVal>
<fAnReVal>
<fNumber>402</fNumber>
<rtnDate alt="12/31/2001">2001-12-31</rtnDate>
<rtnWOSC alt="-20.48">-20.48</rtnWOSC>
<rtnWSC alt="-25.05">-25.05</rtnWSC>
</fAnReVal>
<fAnReVal>
<fNumber>402</fNumber>
<rtnDate alt="12/31/2002">2002-12-31</rtnDate>
<rtnWOSC alt="-42.48">-42.48</rtnWOSC>
<rtnWSC alt="-45.79">-45.79</rtnWSC>
</fAnReVal>
<fAnReVal>
<fNumber>402</fNumber>
<rtnDate alt="12/31/2003">2003-12-31</rtnDate>
<rtnWOSC alt="43.55">43.55</rtnWOSC>
<rtnWSC alt="35.28">35.28</rtnWSC>
</fAnReVal>
<fAnReVal>
<fNumber>402</fNumber>
<rtnDate alt="12/31/2004">2004-12-31</rtnDate>
<rtnWOSC alt="11.96">11.96</rtnWOSC>
<rtnWSC alt="5.53">5.53</rtnWSC>
</fAnReVal>
<fAnReVal>
<fNumber>402</fNumber>
<rtnDate alt="12/31/2005">2005-12-31</rtnDate>
<rtnWOSC alt="5.55">5.55</rtnWOSC>
<rtnWSC alt="-0.51">-0.51</rtnWSC>
</fAnReVal>
<fAnReVal>
<fNumber>402</fNumber>
<rtnDate alt="12/31/2006">2006-12-31</rtnDate>
<rtnWOSC alt="5.03">5.03</rtnWOSC>
<rtnWSC alt="-1.02">-1.02</rtnWSC>
</fAnReVal>
<fAnReVal>
<fNumber>402</fNumber>
<rtnDate alt="12/31/2007">2007-12-31</rtnDate>
<rtnWOSC alt="-1.60">-1.6</rtnWOSC>
<rtnWSC alt="-7.26">-7.26</rtnWSC>
</fAnReVal>
<fAnReVal>
<fNumber>402</fNumber>
<rtnDate alt="12/31/2008">2008-12-31</rtnDate>
<rtnWOSC alt="-10.64">-10.64</rtnWOSC>
<rtnWSC alt="-15.78">-15.78</rtnWSC>
</fAnReVal>
<fAnReVal>
<fNumber>402</fNumber>
<rtnDate alt="12/31/2009">2009-12-31</rtnDate>
<rtnWOSC alt="11.83">11.83</rtnWOSC>
<rtnWSC alt="5.41">5.41</rtnWSC>
</fAnReVal>
<fAnReVal>
<fNumber>402</fNumber>
<rtnDate alt="12/31/2010">2010-12-31</rtnDate>
<rtnWOSC alt="17.28">17.28</rtnWOSC>
<rtnWSC alt="10.54">10.54</rtnWSC>
</fAnReVal>
<fAnReVal>
<fNumber>402</fNumber>
<rtnDate alt="12/31/2011">2011-12-31</rtnDate>
<rtnWOSC alt="8.35">8.35</rtnWOSC>
<rtnWSC alt="2.12">2.12</rtnWSC>
</fAnReVal>
<fAnReVal>
<fNumber>402</fNumber>
<rtnDate alt="12/31/2012">2012-12-31</rtnDate>
<rtnWOSC alt="29.35">29.35</rtnWOSC>
<rtnWSC alt="21.90">21.9</rtnWSC>
</fAnReVal>
<fAnReVal>
<fNumber>402</fNumber>
<rtnDate alt="12/31/2013">2013-12-31</rtnDate>
<rtnWOSC alt="68.64">68.64</rtnWOSC>
<rtnWSC alt="58.95">58.95</rtnWSC>
</fAnReVal>
<fAnReVal>
<fNumber>402</fNumber>
<rtnDate alt="12/31/2014">2014-12-31</rtnDate>
<rtnWOSC alt="33.91">33.91</rtnWOSC>
<rtnWSC alt="26.22">26.22</rtnWSC>
</fAnReVal>
<fAnReVal>
<fNumber>402</fNumber>
<rtnDate alt="12/31/2015">2015-12-31</rtnDate>
<rtnWOSC alt="5.50">5.5</rtnWOSC>
<rtnWSC alt="-0.57">-0.57</rtnWSC>
</fAnReVal>
<fAnReVal>
<fNumber>402</fNumber>
<rtnDate alt="12/31/2016">2016-12-31</rtnDate>
<rtnWOSC alt="-17.16">-17.16</rtnWOSC>
<rtnWSC alt="-21.92">-21.92</rtnWSC>
</fAnReVal>
<bmCalYearDet>
<benchMarkOrder>1</benchMarkOrder>
<bmCalDet>
<calYear>2016</calYear>
<val alt="11.96">11.96</val>
</bmCalDet>
<bmCalDet>
<calYear>2015</calYear>
<val alt="1.38">1.38</val>
</bmCalDet>
<bmCalDet>
<calYear>2014</calYear>
<val alt="13.69">13.69</val>
</bmCalDet>
<bmCalDet>
<calYear>2013</calYear>
<val alt="32.39">32.39</val>
</bmCalDet>
<bmCalDet>
<calYear>2012</calYear>
<val alt="16.00">16</val>
</bmCalDet>
<bmCalDet>
<calYear>2011</calYear>
<val alt="2.11">2.11</val>
</bmCalDet>
<bmCalDet>
<calYear>2010</calYear>
<val alt="15.06">15.06</val>
</bmCalDet>
<bmCalDet>
<calYear>2009</calYear>
<val alt="26.46">26.46</val>
</bmCalDet>
<bmCalDet>
<calYear>2008</calYear>
<val alt="-37.00">-37</val>
</bmCalDet>
<bmCalDet>
<calYear>2007</calYear>
<val alt="5.49">5.49</val>
</bmCalDet>
</bmCalYearDet>
<bmCalYearDet>
<benchMarkOrder>2</benchMarkOrder>
<bmCalDet>
<calYear>2016</calYear>
<val alt="-21.68">-21.68</val>
</bmCalDet>
<bmCalDet>
<calYear>2015</calYear>
<val alt="11.42">11.42</val>
</bmCalDet>
<bmCalDet>
<calYear>2014</calYear>
<val alt="34.32">34.32</val>
</bmCalDet>
<bmCalDet>
<calYear>2013</calYear>
<val alt="65.97">65.97</val>
</bmCalDet>
<bmCalDet>
<calYear>2012</calYear>
<val alt="32.29">32.29</val>
</bmCalDet>
<bmCalDet>
<calYear>2011</calYear>
<val alt="12.08">12.08</val>
</bmCalDet>
<bmCalDet>
<calYear>2010</calYear>
<val alt="15.25">15.25</val>
</bmCalDet>
<bmCalDet>
<calYear>2009</calYear>
<val alt="15.84">15.84</val>
</bmCalDet>
<bmCalDet>
<calYear>2008</calYear>
<val alt="-12.56">-12.56</val>
</bmCalDet>
<bmCalDet>
<calYear>2007</calYear>
<val alt="4.64">4.64</val>
</bmCalDet>
</bmCalYearDet>
</performanceVO>
</catalog>
Currently I have issue with my existing logic when there is no particular year node tree from the xml then the values are getting wrongly mapped.
Tabular data:
2016 2015 2014 2013 2012 2011 2010 2009 2008 2007
rtnWOSC/@alt -17.16 5.5 33.91 68.64 29.35 8.35 17.28 11.83 -10.64 -1.6
rtnWSC/@alt -21.92 -0.57 26.22 58.95 21.9 2.12 10.54 5.41 -15.78 -7.26
val/@alt 11.96 1.38 13.69 32.39 16 2.11 15.06 26.46 -37 5.49
When there is no below node (latest year) for example then the values are getting one td push to left and shows wrongly data of 2015 under 2016
<bmCalDet>
<calYear>2016</calYear>
<val alt="-21.68">-21.68</val>
</bmCalDet>
Below is my XSL:
<xsl:variable name="performanceCount" select="count(catalog/performanceVO/fAnReVal)"/>
<thead>
<tr>
<td></td>
<xsl:for-each select="catalog/performanceVO/fAnReVal">
<xsl:sort data-type="text" select="rtnDate/@alt" order="descending" />
<xsl:if test="position() < 11">
<th>
<xsl:value-of select="substring(rtnDate/@alt, 7, 4)" />
</th>
</xsl:if>
</xsl:for-each>
</tr>
</thead>
<tbody>
<tr>
<xsl:for-each select="catalog/performanceVO/fAnReVal">
<xsl:sort data-type="text" select="rtnDate/@alt" order="descending" />
<xsl:if test="position() < 11">
<td class="text-right">
<xsl:value-of select="$rtnWOSCValue"/>
</td>
</xsl:if>
</xsl:for-each>
</tr>
<tr>
<xsl:for-each select="catalog/performanceVO/bmCalYearDet">
<xsl:sort data-type="text" select="calYear" order="descending" />
<xsl:variable name="calValue" select="val/@alt" />
<xsl:if test="position() <= $performanceCount">
<td class="text-right">
<xsl:sequence select="frk:dash-if-empty($calValue)" />
</td>
</xsl:for-each>
</tr>
</tbody>
It is ok to show as empty value when there is no node available. Any suggestions/pointers?
I have tried your below approach for opposite requirment, under W3schools(https://www.w3schools.com/xml/tryxslt.asp?xmlfile=cdcatalog&xsltfile=cdcatalog) it did not show headings I was able to get variable value
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="bmCalDet-by-year" match="bmCalDet" use="calYear" />
<xsl:template match="/catalog">
<xsl:variable name="years">
<xsl:for-each select="performanceVO/fAnReVal">
<xsl:sort select="rtnDate" order="descending"/>
<xsl:if test="not(position() > 11)">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<h6>Years: <xsl:value-of select="$years" /></h6>
<table border="1">
<tr>
<xsl:for-each select="$years/fAnReVal">
<th>
<h5>inside</h5>
</th>
</xsl:for-each>
</tr>
</table>
</xsl:template>
</xsl:stylesheet>
I could not understand the logic of your XSLT. Is there any reason why you cannot do simply:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:key name="data-by-year" match="fAnReVal" use="substring-before(rtnDate, '-')" />
<xsl:template match="/catalog">
<xsl:variable name="years" select="performanceVO/bmCalYearDet/bmCalDet" />
<table border="1">
<!-- header -->
<tr>
<th/>
<xsl:for-each select="$years">
<th>
<xsl:value-of select="calYear" />
</th>
</xsl:for-each>
</tr>
<!-- 1st row -->
<tr>
<th>rtnWOSC</th>
<xsl:for-each select="$years">
<td>
<xsl:value-of select="key('data-by-year', calYear)/rtnWOSC" />
</td>
</xsl:for-each>
</tr>
<!-- 2nd row -->
<tr>
<th>rtnWSC</th>
<xsl:for-each select="$years">
<td>
<xsl:value-of select="key('data-by-year', calYear)/rtnWSC" />
</td>
</xsl:for-each>
</tr>
<!-- 3rd row -->
<tr>
<th>val</th>
<xsl:for-each select="$years">
<td>
<xsl:value-of select="val" />
</td>
</xsl:for-each>
</tr>
</table>
</xsl:template>
</xsl:stylesheet>
Applied to your input example, the (rendered) result will be:
If you remove a fAnReVal
node, the corresponding cells will be empty. For example, using the same input without this part:
<fAnReVal>
<fNumber>402</fNumber>
<rtnDate alt="12/31/2016">2016-12-31</rtnDate>
<rtnWOSC alt="-17.16">-17.16</rtnWOSC>
<rtnWSC alt="-21.92">-21.92</rtnWSC>
</fAnReVal>
will result in:
Note that this assumes there is at most one fAnReVal
node per year.
To do this in the opposite direction - i.e. create the columns from the 10 most recent fAnReVal
nodes - you could do:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:key name="bmCalDet-by-year" match="bmCalDet" use="calYear" />
<xsl:template match="/catalog">
<xsl:variable name="catalog" select="." />
<xsl:variable name="years">
<xsl:for-each select="performanceVO/fAnReVal">
<xsl:sort select="rtnDate" order="descending"/>
<xsl:if test="position() le 10">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<table border="1">
<!-- header -->
<tr>
<th/>
<xsl:for-each select="$years/fAnReVal">
<th>
<xsl:value-of select="substring-before(rtnDate, '-')" />
</th>
</xsl:for-each>
</tr>
<!-- 1st row -->
<tr>
<th>rtnWOSC</th>
<xsl:for-each select="$years/fAnReVal">
<td>
<xsl:value-of select="rtnWOSC" />
</td>
</xsl:for-each>
</tr>
<!-- 2nd row -->
<tr>
<th>rtnWSC</th>
<xsl:for-each select="$years/fAnReVal">
<td>
<xsl:value-of select="rtnWSC" />
</td>
</xsl:for-each>
</tr>
<!-- 3rd row -->
<tr>
<th>val</th>
<xsl:for-each select="$years/fAnReVal">
<td>
<xsl:value-of select="key('bmCalDet-by-year', substring-before(rtnDate, '-'), $catalog)/val" />
</td>
</xsl:for-each>
</tr>
</table>
</xsl:template>
</xsl:stylesheet>