Reputation: 1552
I need to be able to turn a flat xml data sets into html tables, and I'm having trouble finding syntax examples that will fit my need. I would like to use one stylesheet that can convert similar looking data sets into html tables with variable columns. This means it can't use any hard coded element names besides "rows" and "row".
The stylesheet I'm after would be able to convert:
<?xml version="1.0" encoding="UTF-8"?>
<rows>
<row>
<AccountId>BlPUAA0</AccountId>
<AccountName>Initech</AccountName>
<AcocuntStatus>Client</AcocuntStatus>
</row>
<row>
<AccountId>CJxIAAW</AccountId>
<AccountName>Intertrode</AccountName>
<AcocuntStatus>Prospect</AcocuntStatus>
</row>
</rows>
into:
<table>
<tr>
<th>AccountId</th>
<th>AccountName</th>
<th>AcocuntStatus</th>
</tr>
<tr>
<td>BlPUAA0</td>
<td>Initech</td>
<td>Client</td>
</tr>
<tr>
<td>CJxIAAW</td>
<td>Intertrode</td>
<td>Client</td>
</tr>
</table>
and this:
<?xml version="1.0" encoding="UTF-8"?>
<rows>
<row>
<AccountId>BlPUAA0</AccountId>
<AccountName>Initech</AccountName>
</row>
<row>
<AccountId>CJxIAAW</AccountId>
<AccountName>Intertrode</AccountName>
</row>
</rows>
into this:
<table>
<tr>
<th>AccountId</th>
<th>AccountName</th>
</tr>
<tr>
<td>BlPUAA0</td>
<td>Initech</td>
</tr>
<tr>
<td>CJxIAAW</td>
<td>Intertrode</td>
</tr>
</table>
Upvotes: 7
Views: 41092
Reputation: 169
Few days ago I post an article, hope it can help you: http://web.swfideas.com/?p=12191
Asuming this data:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Edited by XMLSpy -->
<table-node>
<tbody>
<tr>
<td>[C1R1]</td>
<td>[C2R1]</td>
</tr>
<tr>
<td>[C1R2]</td>
<td>[C2R2]</td>
</tr>
<tr>
<td>[C1R3]</td>
<td>[C2R3]</td>
</tr>
</tbody>
</table-node>
Now, the core, our XSLT template:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Coded by SWFideas -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- table template -->
<xsl:template match="table-node">
<table style="border:solid #000000 1px;border-spacing: 0;border-collapse: collapse;">
<xsl:for-each select="tbody">
<tbody>
<xsl:for-each select="tr">
<tr>
<xsl:for-each select="td">
<td style="border:solid #000000 1px; padding: 5px;">
<xsl:value-of select="."/>
</td>
</xsl:for-each>
</tr>
</xsl:for-each>
</tbody>
</xsl:for-each>
<table>
</xsl:template>
</xsl:stylesheet>
In this first approach I’m avoiding to use COLSPAN and another real-life properties (implementation soon, I promise). So the result if we apply our XSLT will be like this:
<table style="border:solid #000000 1px;border-spacing: 0;border-collapse: collapse;">
<tbody>
<tr>
<td style="border:solid #000000 1px; padding: 5px;">[C1R1]</td>
<td style="border:solid #000000 1px; padding: 5px;">[C2R1]</td>
</tr>
<tr>
<td style="border:solid #000000 1px; padding: 5px;">[C1R2]</td>
<td style="border:solid #000000 1px; padding: 5px;">[C2R2]</td>
</tr>
<tr>
<td style="border:solid #000000 1px; padding: 5px;">[C1R3]</td>
<td style="border:solid #000000 1px; padding: 5px;">[C2R3]</td>
</tr>
</tbody>
</table>
You can try it here: http://www.xsltcake.com/slices/gNfh6i/2
Upvotes: 1
Reputation: 1552
I had the urge to try to solve this shortly after posting the question, and here is what I came up with. I guess it makes you wait 24 hours before you can answer it yourself.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="/">
<table>
<tr>
<xsl:for-each select="rows/row[1]/*">
<th>
<xsl:value-of select ="local-name()"/>
</th>
</xsl:for-each>
</tr>
<xsl:for-each select="rows/row">
<tr>
<xsl:for-each select="*">
<td>
<xsl:value-of select="."/>
</td>
</xsl:for-each>
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
Upvotes: 5
Reputation: 243459
A straight-forward and short solution:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/*">
<table><xsl:apply-templates select="row"/></table>
</xsl:template>
<xsl:template match="row[1]">
<tr><xsl:apply-templates select="*" mode="header"/></tr>
<xsl:call-template name="standardRow"/>
</xsl:template>
<xsl:template match="row" name="standardRow">
<tr><xsl:apply-templates select="*"/></tr>
</xsl:template>
<xsl:template match="row/*">
<td><xsl:apply-templates select="node()"/></td>
</xsl:template>
<xsl:template match="row/*" mode="header">
<th><xsl:value-of select="name()"/></th>
</xsl:template>
</xsl:stylesheet>
when applied on the first provided XML document:
<rows>
<row>
<AccountId>BlPUAA0</AccountId>
<AccountName>Initech</AccountName>
<AcocuntStatus>Client</AcocuntStatus>
</row>
<row>
<AccountId>CJxIAAW</AccountId>
<AccountName>Intertrode</AccountName>
<AcocuntStatus>Prospect</AcocuntStatus>
</row>
</rows>
the wanted, correct result is produced:
<table>
<tr>
<th>AccountId</th>
<th>AccountName</th>
<th>AcocuntStatus</th>
</tr>
<tr>
<td>BlPUAA0</td>
<td>Initech</td>
<td>Client</td>
</tr>
<tr>
<td>CJxIAAW</td>
<td>Intertrode</td>
<td>Prospect</td>
</tr>
</table>
when applied on the second provided XML document:
<rows>
<row>
<AccountId>BlPUAA0</AccountId>
<AccountName>Initech</AccountName>
</row>
<row>
<AccountId>CJxIAAW</AccountId>
<AccountName>Intertrode</AccountName>
</row>
</rows>
again the desired, correct result is produced:
<table>
<tr>
<th>AccountId</th>
<th>AccountName</th>
</tr>
<tr>
<td>BlPUAA0</td>
<td>Initech</td>
</tr>
<tr>
<td>CJxIAAW</td>
<td>Intertrode</td>
</tr>
</table>
Upvotes: 8
Reputation: 60414
This stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<table>
<xsl:apply-templates select="rows/row[1]" />
</table>
</xsl:template>
<xsl:template match="row">
<tr>
<xsl:apply-templates mode="th" />
</tr>
<xsl:apply-templates select="../row" mode="td" />
</xsl:template>
<xsl:template match="row/*" mode="th">
<th>
<xsl:value-of select="local-name()" />
</th>
</xsl:template>
<xsl:template match="row" mode="td">
<tr>
<xsl:apply-templates />
</tr>
</xsl:template>
<xsl:template match="row/*">
<td>
<xsl:apply-templates />
</td>
</xsl:template>
</xsl:stylesheet>
Applied to:
<rows>
<row>
<AccountId>BlPUAA0</AccountId>
<AccountName>Initech</AccountName>
<AcocuntStatus>Client</AcocuntStatus>
</row>
<row>
<AccountId>CJxIAAW</AccountId>
<AccountName>Intertrode</AccountName>
<AcocuntStatus>Prospect</AcocuntStatus>
</row>
</rows>
Produces:
<table>
<tr>
<th>AccountId</th>
<th>AccountName</th>
<th>AcocuntStatus</th>
</tr>
<tr>
<td>BlPUAA0</td>
<td>Initech</td>
<td>Client</td>
</tr>
<tr>
<td>CJxIAAW</td>
<td>Intertrode</td>
<td>Prospect</td>
</tr>
</table>
And applied to:
<rows>
<row>
<AccountId>BlPUAA0</AccountId>
<AccountName>Initech</AccountName>
</row>
<row>
<AccountId>CJxIAAW</AccountId>
<AccountName>Intertrode</AccountName>
</row>
</rows>
Produces:
<table>
<tr>
<th>AccountId</th>
<th>AccountName</th>
</tr>
<tr>
<td>BlPUAA0</td>
<td>Initech</td>
</tr>
<tr>
<td>CJxIAAW</td>
<td>Intertrode</td>
</tr>
</table>
Alternatively, this stylesheet produces the same output using a conditional and one fewer template:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<table>
<xsl:apply-templates select="rows/row" />
</table>
</xsl:template>
<xsl:template match="row">
<xsl:if test="position()=1">
<tr>
<xsl:apply-templates mode="th" />
</tr>
</xsl:if>
<tr>
<xsl:apply-templates />
</tr>
</xsl:template>
<xsl:template match="row/*" mode="th">
<th>
<xsl:value-of select="local-name()" />
</th>
</xsl:template>
<xsl:template match="row/*">
<td>
<xsl:apply-templates />
</td>
</xsl:template>
</xsl:stylesheet>
Upvotes: 2