From help I received yesterday I have this code that will parse through an XML file generating an output from various nodes based on the relationships between them.
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@>
<HUSB>@I002@</HUSB>
<WIFE>@I003@</WIFE>
...
</FAM>
<FAM ID=@F002@>
<HUSB>@I004@</HUSB>
<WIFE>@I005@</WIFE>
...
</FAM>
<FAM ID=@F003@>
<HUSB>@I006@</HUSB>
<WIFE>@I007@</WIFE>
...
</FAM>
...
</gedcom>
The way this data works is an individual [INDI] record is related to a family [FAM] record by the id value of its family child [FAMC] node. The family record then relates to two other individual records by the id value of its husband [HUSB] and wife [WIFE] nodes.
This XSLT code will parse through that XML data and properly list the individual records.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:math="http://exslt.org/math"
exclude-result-prefixes="math">
<xsl:include href="math.power.xsl"/>
<xsl:output indent="yes" method="html"/>
<xsl:template match="/">
<html>
<head>
<title>Pedigree Chart</title>
</head>
<body>
<table>
<xsl:apply-templates select="/gedcom/INDI[@ID='@I001@']">
<xsl:with-param name="generation">0</xsl:with-param>
</xsl:apply-templates>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="INDI">
<xsl:param name="generation"/>
<td>
<xsl:attribute name="rowspan">
<xsl:call-template name="math:power">
<xsl:with-param name="base">2</xsl:with-param>
<xsl:with-param name="power"><xsl:value-of select="#url.gens - 1# - $generation"/></xsl:with-param>
</xsl:call-template>
</xsl:attribute>
<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 < #url.gens-1#">
<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 will produce output like this:
<table>
<td rowspan="16">0Ian Lee /SKINNER/<br></td>
<td rowspan="8">1John Howard /SKINNER/<br></td>
<td rowspan="4">2Lee Vernon /SKINNER/<br></td>
<td rowspan="2">3Albert Joshua /SKINNER/<br></td>
<td rowspan="1">4William Harrison /SKINNER/<br></td>
<td rowspan="1">4Anna /FORDYCE/<br></td>
<td rowspan="2">3Pheobe Lucinda /SCOTT/<br></td>
<td rowspan="1">4John M. /SCOTT/<br></td>
<td rowspan="1">4Mary Caroline /DINNELL/<br></td>
<td rowspan="4">2NaDean Adelena /WEHMEYER/<br></td>
<td rowspan="2">3Louis George /WEHMEYER/<br></td>
<td rowspan="1">4August Detrich /WEHMEYER/<br></td>
<td rowspan="1">4Adlina /ELGERT/<br></td>
<td rowspan="2">3Ida Gertrude /KAUFFMAN/<br></td>
<td rowspan="1">4Joseph J. /KAUFFMAN/<br></td>
<td rowspan="1">4Emma /KNAU/<br></td>
<td rowspan="8">1Judy Pauline /JETER/<br></td>
<td rowspan="4">2Killis Walton /JETER/ Jr.<br></td>
<td rowspan="2">3Killis Walton /JETER/<br></td>
<td rowspan="1">4Argulas Beaugard /JETER/<br></td>
<td rowspan="1">4Henrietta Rebeca /COX/<br></td>
<td rowspan="2">3Bertha Maye /OLSEN/<br></td>
<td rowspan="1">4Henry Bertinies /OLSEN/<br></td>
<td rowspan="1">4Martha Ellen /RANEY/<br></td>
<td rowspan="4">2Clara Irene /FARSON/<br></td>
<td rowspan="2">3Harry Herman /FARSON/<br></td>
<td rowspan="1">4Harry Charles /SMITH/<br></td>
<td rowspan="1">4Anna Bell /FARSON/<br></td>
<td rowspan="2">3La Una Jane /LIGHTFRITZ/<br></td>
<td rowspan="1">4/Unknown/<br></td>
<td rowspan="1">4Mary Elizabeth /CONNOR/<br></td>
</table>
I want that output to be grouped like this:
<tr>
<td rowspan="16">0Ian Lee /SKINNER/<br></td>
<td rowspan="8">1John Howard /SKINNER/<br></td>
<td rowspan="4">2Lee Vernon /SKINNER/<br></td>
<td rowspan="2">3Albert Joshua /SKINNER/<br></td>
<td rowspan="1">4William Harrison /SKINNER/<br></td>
</tr>
<tr>
<td rowspan="1">4Anna /FORDYCE/<br></td>
</tr>
<tr>
<td rowspan="2">3Pheobe Lucinda /SCOTT/<br></td>
<td rowspan="1">4John M. /SCOTT/<br></td>
</tr>
<tr>
<td rowspan="1">4Mary Caroline /DINNELL/<br></td>
</tr>
<tr>
<td rowspan="4">2NaDean Adelena /WEHMEYER/<br></td>
<td rowspan="2">3Louis George /WEHMEYER/<br></td>
<td rowspan="1">4August Detrich /WEHMEYER/<br></td>
</tr>
<tr>
<td rowspan="1">4Adlina /ELGERT/<br></td>
</tr>
<tr>
<td rowspan="2">3Ida Gertrude /KAUFFMAN/<br></td>
<td rowspan="1">4Joseph J. /KAUFFMAN/<br></td>
</tr>
<tr>
<td rowspan="1">4Emma /KNAU/<br></td>
</tr>
<tr>
<td rowspan="8">1Judy Pauline /JETER/<br></td>
<td rowspan="4">2Killis Walton /JETER/ Jr.<br></td>
<td rowspan="2">3Killis Walton /JETER/<br></td>
<td rowspan="1">4Argulas Beaugard /JETER/<br></td>
</tr>
<tr>
<td rowspan="1">4Henrietta Rebeca /COX/<br></td>
</tr>
<tr>
<td rowspan="2">3Bertha Maye /OLSEN/<br></td>
<td rowspan="1">4Henry Bertinies /OLSEN/<br></td>
</tr>
<tr>
<td rowspan="1">4Martha Ellen /RANEY/<br></td>
</tr>
<tr>
<td rowspan="4">2Clara Irene /FARSON/<br></td>
<td rowspan="2">3Harry Herman /FARSON/<br></td>
<td rowspan="1">4Harry Charles /SMITH/<br></td>
</tr>
<tr>
<td rowspan="1">4Anna Bell /FARSON/<br></td>
</tr>
<tr>
<td rowspan="2">3La Una Jane /LIGHTFRITZ/<br></td>
<td rowspan="1">4/Unknown/<br></td>
</tr>
<tr>
<td rowspan="1">4Mary Elizabeth /CONNOR/<br></td>
</tr>
I have this demonstration xslt that will create the desired grouping without relation to the XML.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:math="http://exslt.org/math"
exclude-result-prefixes="math">
<xsl:include href="math.power.xsl"/>
<xsl:template match="/">
<p>Recursive Table Loop</p>
<table border="1" cellspacing="0" cellpadding="5">
<xsl:call-template name="rows">
<xsl:with-param name="row" select="0"/>
</xsl:call-template>
</table>
</xsl:template>
<xsl:template name="rows">
<xsl:param name="row"/>
<tr>
<xsl:call-template name="cells">
<xsl:with-param name="row" select="$row"/>
<xsl:with-param name="cell" select="4"/>
</xsl:call-template>
</tr>
<xsl:if test="$row < 15">
<xsl:call-template name="rows">
<xsl:with-param name="row" select="$row + 1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="cells">
<xsl:param name="row"/>
<xsl:param name="cell"/>
<xsl:variable name="outputCell">
<xsl:call-template name="math:power">
<xsl:with-param name="base">2</xsl:with-param>
<xsl:with-param name="power"><xsl:value-of select="$cell"/></xsl:with-param>
</xsl:call-template>
</xsl:variable>
<xsl:if test="$row mod $outputCell = 0">
<td>
<xsl:attribute name="rowspan">
<xsl:value-of select="$outputCell"/>
</xsl:attribute>
<xsl:value-of select="$row"/> :
<xsl:value-of select="$cell"/> :
<xsl:value-of select="$outputCell"/>
</td>
</xsl:if>
<xsl:if test="$cell > 0">
<xsl:call-template name="cells">
<xsl:with-param name="row" select="$row"/>
<xsl:with-param name="cell" select="$cell - 1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
This will produce a table with the desired row spanning cells like this.
p>Recursive Table Loop</p>
<table cellspacing="0" cellpadding="5" border="1">
<tr>
<td rowspan="16">0 : 4 : 16</td>
<td rowspan="8">0 : 3 : 8</td>
<td rowspan="4">0 : 2 : 4</td>
<td rowspan="2">0 : 1 : 2</td>
<td rowspan="1">0 : 0 : 1</td>
</tr>
<tr>
<td rowspan="1">1 : 0 : 1</td>
</tr>
<tr>
<td rowspan="2">2 : 1 : 2</td>
<td rowspan="1">2 : 0 : 1</td>
</tr>
<tr>
<td rowspan="1">3 : 0 : 1</td>
</tr>
<tr>
<td rowspan="4">4 : 2 : 4</td>
<td rowspan="2">4 : 1 : 2</td>
<td rowspan="1">4 : 0 : 1</td>
</tr>
<tr>
<td rowspan="1">5 : 0 : 1</td>
</tr>
<tr>
<td rowspan="2">6 : 1 : 2</td>
<td rowspan="1">6 : 0 : 1</td>
</tr>
<tr>
<td rowspan="1">7 : 0 : 1</td>
</tr>
<tr>
<td rowspan="8">8 : 3 : 8</td>
<td rowspan="4">8 : 2 : 4</td>
<td rowspan="2">8 : 1 : 2</td>
<td rowspan="1">8 : 0 : 1</td>
</tr>
<tr>
<td rowspan="1">9 : 0 : 1</td>
</tr>
<tr>
<td rowspan="2">10 : 1 : 2</td>
<td rowspan="1">10 : 0 : 1</td>
</tr>
<tr>
<td rowspan="1">11 : 0 : 1</td>
</tr>
<tr>
<td rowspan="4">12 : 2 : 4</td>
<td rowspan="2">12 : 1 : 2</td>
<td rowspan="1">12 : 0 : 1</td>
</tr>
<tr>
<td rowspan="1">13 : 0 : 1</td>
</tr>
<tr>
<td rowspan="2">14 : 1 : 2</td>
<td rowspan="1">14 : 0 : 1</td>
</tr>
<tr>
<td rowspan="1">15 : 0 : 1</td>
</tr>
</table>
But I can not figure out how to marry the two XSLT codes together. The trouble is that in the first code the INDI is the base of a multiple function recursive loop. And I just can not figure out how to break out of that loop at the relevant points to wrap the content in table row <tr> tags.