Thanks to some great help for my first ever post on this formum [
Fetch a node based on a value of another node.] I am now recursively traversing through my XML data where nodes are related to each other.
Example XML
<gedcom>
<INDI ID="@I001@">
...
<FAMC>@F001@</FAMC>
</INDI>
<INDI ID="@I002@">
...
<FAMC>@F002@</FAMC>
</INDI>
<INDI ID="@I003@">
...
<FAMC>@F003@</FAMC>
</INDI>
...
<FAM ID="@F001@</FAM>
...
<HUSB>@I002@</HUSB>
<WIFE>@I003@</WIFE>
</FAM>
<FAM ID="@F002@</FAM>
...
<HUSB>@I004@</HUSB>
<WIFE>@I005@</WIFE>
</FAM>
<FAM ID="@F003@</FAM>
...
<HUSB>@I006@</HUSB>
<WIFE>@I007@</WIFE>
</FAM>
...
</gedcom>
Here is my current XSLT code
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="html"/>
<xsl:template match="/">
<html>
<head>
<title>Pedigree Chart</title>
</head>
<body>
<table>
<tr>
<xsl:apply-templates select="/gedcom/INDI[@ID='@I001@']">
<xsl:with-param name="generation">0</xsl:with-param>
</xsl:apply-templates>
</tr>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="INDI">
<xsl:param name="generation"/>
<td>
<xsl:value-of select="$generation"/>
<xsl:value-of select="./NAME/text()"/><br/>
</td>
<xsl:apply-templates select="FAMC">
<xsl:with-param name="generation">
<xsl:value-of select="$generation"/>
</xsl:with-param>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="FAMC">
<xsl:param name="generation"/>
<xsl:if test="$generation < 4">
<xsl:variable name="data" select="."/>
<xsl:apply-templates select="../../FAM[@ID=$data]">
<xsl:with-param name="generation">
<xsl:value-of select="$generation + 1"/>
</xsl:with-param>
</xsl:apply-templates>
</xsl:if>
</xsl:template>
<xsl:template match="FAM">
<xsl:param name="generation"/>
<xsl:apply-templates select="HUSB|WIFE">
<xsl:with-param name="generation">
<xsl:value-of select="$generation"/>
</xsl:with-param>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="HUSB|WIFE">
<xsl:param name="generation"/>
<xsl:variable name="data" select="."/>
<xsl:apply-templates select="../../INDI[@ID=$data]">
<xsl:with-param name="generation">
<xsl:value-of select="$generation"/>
</xsl:with-param>
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
This produces all the desired xml nodes in the output, but they are all in a single table row. What I desire is a table row once each 5th generation is reached ($generations = 4).
It should look something like this:
<table>
<tr>
<td rowspan="16">generation 0</td>
<td rowspan="8">generation 1</td>
<td rowspan="4">generation 2</td>
<td rowspan="2">generation 3</td>
<td rowspan="1">generation 4</td>
</tr>
<tr>
<td rowspan="1">generation 4</td>
</tr>
<tr>
<td rowspan="2">generation 3</td>
<td rowspan="1">generation 4</td>
</tr>
<tr>
<td rowspan="1">generation 4</td>
</tr>
<tr>
<td rowspan="4">generation 2</td>
<td rowspan="2">generation 3</td>
<td rowspan="1">generation 4</td>
</tr>
<tr>
<td rowspan="1">generation 4</td>
</tr>
<tr>
<td rowspan="2">generation 3</td>
<td rowspan="1">generation 4</td>
</tr>
<tr>
<td rowspan="1">generation 4</td>
</tr>
...
</table>
I have XSLT logic to properly calculate the rowspan attributes of each cell and to substitute content of the <td></td> nodes with actual data from the XML document. But I have no idea how to properly wrap the correct number of cells in <tr></tr> table rows.
I tried a trick I often use in procedural programming, but the XSLT parser did not like it as it does not properly nest tags.
<xsl:template match="INDI">
<xsl:param name="generation"/>
<td>
<xsl:value-of select="$generation"/>
<xsl:value-of select="./NAME/text()"/><br/>
</td>
<xsl:apply-templates select="FAMC">
<xsl:with-param name="generation">
<xsl:value-of select="$generation"/>
</xsl:with-param>
</xsl:apply-templates>
<xsl:if test="$generation = 4">
<!-- reached the end of a row, close the current row tag and open a new row -->
</tr>
<tr>
</xsl:if>
</xsl:template>
Can anybody guide me to the XSLT method to do this type of logic.
TIA
Ian