Use xslt to convert xml list of structured objects into html table with multiple columns
I have following piece of XML file:
<PASS>
<FIRMWARE Unit="1" Group="FIRM">
<test name="ACPI" ID="ACPI" />
</FIRMWARE>
<NETWORK Unit="2" Group="NTWK">
<test name="Controller Test" ID="Ctlr" />
</NETWORK>
<NETWORK Unit="1" Group="NTWK">
<test name="Controller Test" ID="Ctlr" />
</NETWORK>
<ATA Unit="1" Group="ATA-">
<test name="Serial Controllers" ID="SATA" />
</ATA>
<PARALLEL_PORT Unit="1" Group="LPT-">
<test name="Verify Controller" ID="Ctrl" />
<test name="Check Status Port" ID="Stat" />
<test name="Interrupt Test" ID="Int-" />
</PARALLEL_PORT>
<SERIAL_PORT Unit="4" Group="COM-">
<test name="Interrupt" ID="Intr" />
<test name="Line Control" ID="Line" />
<test name="Test Loopback" ID="LpBk" />
<test name="Test Internal FIFO" ID="FIFO" />
<test name="Test Internal Loopback" ID="ILBk" />
</SERIAL_PORT>
<SERIAL_PORT Unit="3" Group="COM-">
<test name="Interrupt" ID="Intr" />
<test name="Line Control" ID="Line" />
<test name="Test Loopback" ID="LpBk" />
<test name="Test Internal FIFO" ID="FIFO" />
<test name="Test Internal Loopback" ID="ILBk" />
</SERIAL_PORT>
</PASS>
With the existing XSL file I get all test results in one column. This is not very practical for printing and so on. How can I create a table with 2 or more columns?
<xsl:template match="PASS">
<div class="component">
<h4>PASSED</h4>
<xsl:call-template name="outputtable">
<xsl:with-param name="result" select="'PASSED'" />
</xsl:call-template>
</div>
</xsl:template>
<xsl:template name="outputtable">
<div class="attributes">
<xsl:variable name="resultlist" select="*" />
<xsl:variable name="index" select="count(child::*)" />
<xsl:for-each select="$resultlist">
<xsl:variable name="Unit" select="@Unit" />
<xsl:variable name="Group" select="@Group" />
<p class="attrtitle">
<xsl:value-of select="name()" />
Unit:
<xsl:value-of select="$Unit" />
</p>
<xsl:variable name="testtype" select="*" />
<xsl:for-each select="$testtype">
<p class="attribute">
<xsl:value-of select="@name" />
</p>
</xsl:for-each>
<p />
</xsl:for-each>
</div>
I've already searched for solution and found following links: Use xslt to convert xml list into html table with multiple columns and http://blogs.msdn.com/b/kaevans/archive/2003/04/03/4754.aspx
The situation I have is rather different I have structured objects and not simple as "Item" or "ComputerName" and the other drawback is that those test are not of the same type (, etc.). This XML report is constructed automatically by non-OSS software, so I h开发者_如何学Pythonave no way to change it at creation time.
I'll be glad to get any ideas!
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pnumCols" select="3"/>
<xsl:template match="PASS">
<div class="component">
<h4>PASSED</h4>
<div class="attributes">
<table border="1">
<xsl:apply-templates select=
"*[position() mod $pnumCols = 1]"/>
</table>
</div>
</div>
</xsl:template>
<xsl:template match="PASS/*">
<tr>
<xsl:apply-templates mode="process" select=
".|following-sibling::*[not(position() > $pnumCols -1)]"/>
</tr>
</xsl:template>
<xsl:template match="PASS/*" mode="process">
<xsl:variable name="Unit" select="@Unit" />
<xsl:variable name="Group" select="@Group" />
<td>
<p class="attrtitle">
<xsl:value-of select="name()" /> Unit:
<xsl:value-of select="$Unit" />
</p>
<xsl:variable name="testtype" select="*" />
<xsl:for-each select="$testtype">
<p class="attribute">
<xsl:value-of select="@name" />
</p>
</xsl:for-each>
<p />
</td>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<PASS>
<FIRMWARE Unit="1" Group="FIRM">
<test name="ACPI" ID="ACPI" />
</FIRMWARE>
<NETWORK Unit="2" Group="NTWK">
<test name="Controller Test" ID="Ctlr" />
</NETWORK>
<NETWORK Unit="1" Group="NTWK">
<test name="Controller Test" ID="Ctlr" />
</NETWORK>
<ATA Unit="1" Group="ATA-">
<test name="Serial Controllers" ID="SATA" />
</ATA>
<PARALLEL_PORT Unit="1" Group="LPT-">
<test name="Verify Controller" ID="Ctrl" />
<test name="Check Status Port" ID="Stat" />
<test name="Interrupt Test" ID="Int-" />
</PARALLEL_PORT>
<SERIAL_PORT Unit="4" Group="COM-">
<test name="Interrupt" ID="Intr" />
<test name="Line Control" ID="Line" />
<test name="Test Loopback" ID="LpBk" />
<test name="Test Internal FIFO" ID="FIFO" />
<test name="Test Internal Loopback" ID="ILBk" />
</SERIAL_PORT>
<SERIAL_PORT Unit="3" Group="COM-">
<test name="Interrupt" ID="Intr" />
<test name="Line Control" ID="Line" />
<test name="Test Loopback" ID="LpBk" />
<test name="Test Internal FIFO" ID="FIFO" />
<test name="Test Internal Loopback" ID="ILBk" />
</SERIAL_PORT>
</PASS>
produces the results in $pnumCols
-column format, in this specific case pnumCols
is 3:
<div class="component">
<h4>PASSED</h4>
<div class="attributes">
<table border="1">
<tr>
<td>
<p class="attrtitle">FIRMWARE Unit:
1</p>
<p class="attribute">ACPI</p>
<p/>
</td>
<td>
<p class="attrtitle">NETWORK Unit:
2</p>
<p class="attribute">Controller Test</p>
<p/>
</td>
<td>
<p class="attrtitle">NETWORK Unit:
1</p>
<p class="attribute">Controller Test</p>
<p/>
</td>
</tr>
<tr>
<td>
<p class="attrtitle">ATA Unit:
1</p>
<p class="attribute">Serial Controllers</p>
<p/>
</td>
<td>
<p class="attrtitle">PARALLEL_PORT Unit:
1</p>
<p class="attribute">Verify Controller</p>
<p class="attribute">Check Status Port</p>
<p class="attribute">Interrupt Test</p>
<p/>
</td>
<td>
<p class="attrtitle">SERIAL_PORT Unit:
4</p>
<p class="attribute">Interrupt</p>
<p class="attribute">Line Control</p>
<p class="attribute">Test Loopback</p>
<p class="attribute">Test Internal FIFO</p>
<p class="attribute">Test Internal Loopback</p>
<p/>
</td>
</tr>
<tr>
<td>
<p class="attrtitle">SERIAL_PORT Unit:
3</p>
<p class="attribute">Interrupt</p>
<p class="attribute">Line Control</p>
<p class="attribute">Test Loopback</p>
<p class="attribute">Test Internal FIFO</p>
<p class="attribute">Test Internal Loopback</p>
<p/>
</td>
</tr>
</table>
</div>
</div>
Explanation: We use two templates -- one for wrapping a group of $pnumCols
consecutive results in a row, the other, in mode="process"
, to actually produce the contents within that row.
精彩评论