Reputation: 555
I'm trying to transform my XML to an HTML table but still quite confused with how to do row-column mapping using templates. My XML definition is:
<Table>
<Parent>
<Head>Header 1</Head>
<Children>
<Node>Node 1</Node>
<Node>Node 2</Node>
<Node>Node 3</Node>
</Children>
</Parent>
<Parent>
<Head>Header 2</Head>
<Children>
<Node>Node 4</Node>
<Node>Node 5</Node>
<Node>Node 6</Node>
</Children>
</Parent>
</Table>
Expected HTML output:
<table>
<tr>
<td>Header 1</td>
<td>Header 2</td>
</tr>
<tr>
<td>Node 1</td>
<td>Node 4</td>
</tr>
<tr>
<td>Node 2</td>
<td>Node 5</td>
</tr>
<tr>
<td>Node 3</td>
<td>Node 6</td>
</tr>
</table>
I've used template matching but can't figure out how to do the mapping by position. This is my current XSLT code:
<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:template match="Table">
<table>
<tr>
<xsl:apply-templates select="Parent"/>
</tr>
<xsl:apply-templates select="Parent/Children"/>
</table>
</xsl:template>
<xsl:template match="Parent">
<td>
<xsl:value-of select="Head"/>
</td>
</xsl:template>
<xsl:template match="Parent/Children">
<tr>
<xsl:apply-templates/>
</tr>
</xsl:template>
<xsl:template match="Parent/Children/Node">
<td>
<xsl:value-of select="."/>
</td>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0
Views: 474
Reputation: 70598
If you can assume each Parent
has the same number of nodes, you can start off by selecting just the nodes of the first Parent, as these will then represent the start of each new row
<xsl:apply-templates select="Parent[1]/Children/Node" mode="row"/>
(The mode
is used here, because the final XSLT will have multiple templates matching Node
)
Then, for the template that matches these nodes, you create a new table row, and copy in the child nodes from all parents that in the same position in the XSLT:
<xsl:template match="Node" mode="row">
<tr>
<xsl:apply-templates select="../../../Parent/Children/Node[position() = current()/position()]" />
</tr>
</xsl:template>
Try this XSLT
<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:template match="Table">
<table>
<tr>
<xsl:apply-templates select="Parent"/>
</tr>
<xsl:apply-templates select="Parent[1]/Children/Node" mode="row"/>
</table>
</xsl:template>
<xsl:template match="Parent">
<td>
<xsl:value-of select="Head"/>
</td>
</xsl:template>
<xsl:template match="Node" mode="row">
<xsl:variable name="pos" select="position()" />
<tr>
<xsl:apply-templates select="../../../Parent/Children/Node[position() = $pos]" />
</tr>
</xsl:template>
<xsl:template match="Node">
<td>
<xsl:value-of select="."/>
</td>
</xsl:template>
</xsl:stylesheet>
Upvotes: 2