So I have an xml document that does not contain the full cross product in the final table but I need the xslt to put the blanks in for me. If you run this xslt you can see that GCM should be under ABC. I know that I must need to count result and then add a blank but I am stuck.
<root>
<Cell>
<place>BRM</place>
<test>DMC</test>
<Score>70</Score>
<Colour>#008000</Colour>
<GenerateDate>2012-04-04 12:46:41</GenerateDate>
<testgroup> Process Plant</testgroup>
</Cell>
<Cell>
<place>GCM</place>
<test>DMC</test>
<Score>76</Score>
<Colour>#008000</Colour>
<GenerateDate>2012-04-04 12:46:41</GenerateDate>
<testgroup> Process Plant</testgroup>
</Cell>
<Cell>
<place>GRM</place>
<test>DMC</test>
<Score>72</Score>
<Colour>#008000</Colour>
<GenerateDate>2012-04-04 12:46:41</GenerateDate>
<testgroup> Process Plant</testgroup>
</Cell>
<Cell>
<place>NPM</place>
<test>DMC</test>
<Score>80</Score>
<Colour>#008000</Colour>
<GenerateDate>2012-04-04 12:46:41</GenerateDate>
<testgroup> Process Plant</testgroup>
</Cell>
<Cell>
<place>PDM</place>
<test>DMC</test>
<Score>88</Score>
<Colour>#008000</Colour>
<GenerateDate>2012-04-04 12:46:41</GenerateDate>
<testgroup> Process Plant</testgroup>
</Cell>
<Cell>
<place>PTM</place>
<test>DMC</test>
<Score>58</Score>
<Colour>#FFA100</Colour>
<GenerateDate>2012-04-04 12:46:41</GenerateDate>
<testgroup> Process Plant</testgroup>
</Cell>
<Cell>
<place>SRM</place>
<test>DMC</test>
<Score>62</Score>
<Colour>#FFA100</Colour>
<GenerateDate>2012-04-04 12:46:41</GenerateDate>
<testgroup> Process Plant</testgroup>
</Cell>
<Cell>
<place>SWC</place>
<test>DMC</test>
<Score>85</Score>
<Colour>#008000</Colour>
<GenerateDate>2012-04-04 12:46:41</GenerateDate>
<testgroup> Process Plant</testgroup>
</Cell>
<Cell>
<place>RVS</place>
<test>DMC</test>
<Score>84</Score>
<Colour>#008000</Colour>
<GenerateDate>2012-04-04 12:46:41</GenerateDate>
<testgroup> Process Plant</testgroup>
</Cell>
<Cell>
<place>BWM</place>
<test>SUR</test>
<Score>66</Score>
<Colour>#FFA100</Colour>
<GenerateDate>2012-04-04 12:46:41</GenerateDate>
<testgroup>Survey</testgroup>
</Cell>
<Cell>
<place>PDM</place>
<test>SUR</test>
<Score>85</Score>
<Colour>#008000</Colour>
<GenerateDate>2012-04-04 12:46:41</GenerateDate>
<testgroup>Survey</testgroup>
</Cell>
<Cell>
<place>SRM</place>
<test>SUR</test>
<Score>41</Score>
<Colour>#FFA100</Colour>
<GenerateDate>2012-04-04 12:46:41</GenerateDate>
<testgroup>Survey</testgroup>
</Cell>
</root>
XSLT
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="html" indent="yes"/>
<xsl:key name="muench" match="/root/Cell/place" use="."/>
<xsl:key name="test-key" match="/root/Cell/test" use="."/>
<xsl:template match="/">
<html>
<head>
<title>ABC test Report</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
</head>
<body >
<div >
<header>
<h2 >
test group - <xsl:value-of select="/root/Cell/testgroup"/>
</h2>
</header>
<div class="content">
<table >
<thead>
<tr>
<th >Place</th>
<xsl:for-each select="/root/Cell/test[generate-id() = generate-id(key('test-key',.)[1])]">
<th >
<xsl:value-of select="."/>
</th>
</xsl:for-each>
</tr>
</thead>
<tbody>
<xsl:for-each select="/root/Cell/place[generate-id() = generate-id(key('muench',.)[1])]">
<xsl:call-template name="pivot">
<xsl:with-param name="place" select="."/>
</xsl:call-template>
</xsl:for-each>
</tbody>
</table>
</div>
<footer >
<p></p>
</footer>
</div>
</body>
</html>
</xsl:template>
<xsl:template name="pivot">
<xsl:param name="place"/>
<tr>
<td >
<xsl:value-of select="$place"/>
</td>
<xsl:for-each select="/root/Cell/test[generate-id() = generate-id(key('test-key',.)[1])]">
<xsl:for-each select="/root/Cell[place=$place and test=.]">
<xsl:choose>
<xsl:when test="count(.)=1">
<td>
<xsl:attribute name="style">
background-color:<xsl:value-of select="Colour"/>;
</xsl:attribute>
<xsl:value-of select="Score"/>%
</td>
</xsl:when>
<xsl:otherwise>
<td>
</td>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:for-each>
</tr>
</xsl:template>
</xsl:stylesheet>
output I wanted
<html>
<table border="1">
<thead>
<th>Place</th>
<th>DMC</th>
<th>SUR</th>
</thead>
<tbody>
<tr>
<td>BRM</td>
<td> 70</td>
<td> </td>
</tr>
<tr>
<td>BWM</td>
<td> </td>
<td> 66</td>
</tr>
<tr>
<td>GCM</td>
<td> 76</td>
<td> </td>
</tr>
<tr>
<td>GRM</td>
<td> 72</td>
<td> </td>
</tr>
<tr>
<td>NPM</td>
<td> 80</td>
<td> </td>
</tr>
<tr>
<td>PDM</td>
<td> 88</td>
<td> 85</td>
</tr>
<tr>
<td>PTM</td>
<td> 58</td>
<td> </td>
</tr>
<tr>
<td>RVS</td>
<td> 84</td>
<td> </td>
</tr>
<tr>
<td>SRM</td>
<td> 62</td>
<td> 41</td>
</tr>
<tr>
<td>SWC</td>
<td> 85</td>
<td> </td>
</tr>
</tbody>
</table>
</html>
This shorter and simpler transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kTests" match="test" use="."/>
<xsl:key name="kCellByPlace" match="Cell" use="place"/>
<xsl:variable name="vTests" select=
"/*/*/test
[generate-id()
=
generate-id(key('kTests', .)[1])
]
"/>
<xsl:template match="/*">
<html>
<table border="1">
<thead>
<th>Place</th>
<xsl:apply-templates select="$vTests"/>
</thead>
<tbody>
<xsl:apply-templates select=
"Cell[generate-id() = generate-id(key('kCellByPlace', place))]">
<xsl:sort select="place"/>
</xsl:apply-templates>
</tbody>
</table>
</html>
</xsl:template>
<xsl:template match="test">
<th><xsl:value-of select="."/></th>
</xsl:template>
<xsl:template match="Cell">
<tr>
<td><xsl:value-of select="place"/></td>
<xsl:apply-templates select="$vTests" mode="row">
<xsl:with-param name="pCells" select="key('kCellByPlace', place)"/>
</xsl:apply-templates>
</tr>
</xsl:template>
<xsl:template match="test" mode="row">
<xsl:param name="pCells"/>
<td>
<xsl:value-of select=
"concat(' ',$pCells[test=current()]/Score)"/>
</td>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<root>
<Cell>
<place>BRM</place>
<test>DMC</test>
<Score>70</Score>
<Colour>#008000</Colour>
<GenerateDate>2012-04-04 12:46:41</GenerateDate>
<testgroup> Process Plant</testgroup>
</Cell>
<Cell>
<place>GCM</place>
<test>DMC</test>
<Score>76</Score>
<Colour>#008000</Colour>
<GenerateDate>2012-04-04 12:46:41</GenerateDate>
<testgroup> Process Plant</testgroup>
</Cell>
<Cell>
<place>GRM</place>
<test>DMC</test>
<Score>72</Score>
<Colour>#008000</Colour>
<GenerateDate>2012-04-04 12:46:41</GenerateDate>
<testgroup> Process Plant</testgroup>
</Cell>
<Cell>
<place>NPM</place>
<test>DMC</test>
<Score>80</Score>
<Colour>#008000</Colour>
<GenerateDate>2012-04-04 12:46:41</GenerateDate>
<testgroup> Process Plant</testgroup>
</Cell>
<Cell>
<place>PDM</place>
<test>DMC</test>
<Score>88</Score>
<Colour>#008000</Colour>
<GenerateDate>2012-04-04 12:46:41</GenerateDate>
<testgroup> Process Plant</testgroup>
</Cell>
<Cell>
<place>PTM</place>
<test>DMC</test>
<Score>58</Score>
<Colour>#FFA100</Colour>
<GenerateDate>2012-04-04 12:46:41</GenerateDate>
<testgroup> Process Plant</testgroup>
</Cell>
<Cell>
<place>SRM</place>
<test>DMC</test>
<Score>62</Score>
<Colour>#FFA100</Colour>
<GenerateDate>2012-04-04 12:46:41</GenerateDate>
<testgroup> Process Plant</testgroup>
</Cell>
<Cell>
<place>SWC</place>
<test>DMC</test>
<Score>85</Score>
<Colour>#008000</Colour>
<GenerateDate>2012-04-04 12:46:41</GenerateDate>
<testgroup> Process Plant</testgroup>
</Cell>
<Cell>
<place>RVS</place>
<test>DMC</test>
<Score>84</Score>
<Colour>#008000</Colour>
<GenerateDate>2012-04-04 12:46:41</GenerateDate>
<testgroup> Process Plant</testgroup>
</Cell>
<Cell>
<place>BWM</place>
<test>SUR</test>
<Score>66</Score>
<Colour>#FFA100</Colour>
<GenerateDate>2012-04-04 12:46:41</GenerateDate>
<testgroup>Survey</testgroup>
</Cell>
<Cell>
<place>PDM</place>
<test>SUR</test>
<Score>85</Score>
<Colour>#008000</Colour>
<GenerateDate>2012-04-04 12:46:41</GenerateDate>
<testgroup>Survey</testgroup>
</Cell>
<Cell>
<place>SRM</place>
<test>SUR</test>
<Score>41</Score>
<Colour>#FFA100</Colour>
<GenerateDate>2012-04-04 12:46:41</GenerateDate>
<testgroup>Survey</testgroup>
</Cell>
</root>
produces the wanted result :
<html>
<table border="1">
<thead>
<th>Place</th>
<th>DMC</th>
<th>SUR</th>
</thead>
<tbody>
<tr>
<td>BRM</td>
<td> 70</td>
<td> </td>
</tr>
<tr>
<td>BWM</td>
<td> </td>
<td> 66</td>
</tr>
<tr>
<td>GCM</td>
<td> 76</td>
<td> </td>
</tr>
<tr>
<td>GRM</td>
<td> 72</td>
<td> </td>
</tr>
<tr>
<td>NPM</td>
<td> 80</td>
<td> </td>
</tr>
<tr>
<td>PDM</td>
<td> 88</td>
<td> 85</td>
</tr>
<tr>
<td>PTM</td>
<td> 58</td>
<td> </td>
</tr>
<tr>
<td>RVS</td>
<td> 84</td>
<td> </td>
</tr>
<tr>
<td>SRM</td>
<td> 62</td>
<td> 41</td>
</tr>
<tr>
<td>SWC</td>
<td> 85</td>
<td> </td>
</tr>
</tbody>
</table>
</html>
Explanation:
We create an auxiliary variable $vTests
that contains all distinct values for a test
element.
Whenever we want to generate a tr
that contains the score for a particular test at particular place, we generate "empty" td
s for all test
elements contained in $vTests
, whose string value isn't equal to the string value of the specific test
element, and we generate the string value of the Score
sibling of the particular test
element exactly when the string value of this test
element is equal to the current test
element from $vTests
.
Thanks to Dimetre for the help. He showed how to use templates more effectively and created the variable. I then used this to edit his script to give the output I was looking for.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kTests" match="test" use="."/>
<xsl:variable name="vTests" select=
"/*/*/test
[generate-id()
=
generate-id(key('kTests', .)[1])
]
"/>
<xsl:key name="kPlaces" match="place" use="."/>
<xsl:variable name="vPlaces" select=
"/*/*/place
[generate-id()
=
generate-id(key('kPlaces', .)[1])
]
"/>
<xsl:template match="/*">
<html>
<table border="1">
<thead>
<th>Place</th>
<xsl:apply-templates select="$vTests">
<xsl:sort select="." />
</xsl:apply-templates>
</thead>
<tbody>
<xsl:apply-templates select="$vPlaces">
<xsl:sort select="." />
</xsl:apply-templates>
</tbody>
</table>
</html>
</xsl:template>
<xsl:template match="test">
<th><xsl:value-of select="."/></th>
</xsl:template>
<xsl:template match="place">
<tr>
<td><xsl:value-of select="."/></td>
<xsl:apply-templates select="$vTests" mode="row">
<xsl:sort select="." />
<xsl:with-param name="pPlace" select="."/>
</xsl:apply-templates>
</tr>
</xsl:template>
<xsl:template match="test" mode="row">
<xsl:param name="pPlace"/>
<td>
<xsl:value-of select=
"concat(' ',/root/Cell[test=current() and place=$pPlace]/Score)"/>
</td>
</xsl:template>
</xsl:stylesheet>