This conversion is :
<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="RowAttribsByName" match="Row/@*" use="concat(generate-id(..), '|', name())"/> <xsl:variable name="vColNames" select= "/*/Columns/*[not(@Hidden = 'true')]/@Name"/> <xsl:template match="/*"> <table border="1"> <tr> <xsl:apply-templates select="Columns/*"/> </tr> <xsl:apply-templates select="Rows/Row"/> </table> </xsl:template> <xsl:template match="Column[not(@Hidden = 'true')]"> <td><xsl:value-of select="@Caption"/></td> </xsl:template> <xsl:template match="Row"> <tr> <xsl:apply-templates select="$vColNames"> <xsl:with-param name="pRowId" select="generate-id()"/> </xsl:apply-templates> </tr> </xsl:template> <xsl:template match="Column/@*"> <xsl:param name="pRowId"/> <td width="50%"> <xsl:value-of select= "key('RowAttribsByName', concat($pRowId, '|', .) ) "/> </td> </xsl:template> </xsl:stylesheet>
when applied to the provided XML document :
<TableData> <Columns> <Column Name="ID" Hidden="true" /> <Column Name="Name" Caption="Item Name" /> <Column Name="Desc" Caption="Item Description" /> </Columns> <Rows> <Row ID="0" Name="A" /> <Row ID="1" Name="B" Desc="Some description"/> <Row ID="3" Name="C" /> </Rows> </TableData>
creates the desired, correct result :
<table border="1"> <tr> <td>Item Name</td> <td>Item Description</td> </tr> <tr> <td width="50%">A</td> <td width="50%"/> </tr> <tr> <td width="50%">B</td> <td width="50%">Some description</td> </tr> <tr> <td width="50%">C</td> <td width="50%"/> </tr> </table>
source share