I think I've solved your problem. I used Saxon 8.7J to process the XSLT.
I cut down your XML so that I could work only on the part that was presenting
the challenge. I retained the orginal root element, but excised all other
elements but <free-xml> and its children. When you adapt my solution to the
original document you will want to pay attention to the XPath expressions to
insure that you point to the correct elements.
The entire stylesheet is posted at the end of this message, but I will
highlight sections of it here for exposition.
The first problem we had to solve was how to handle the irregular and unknown
number of rows to be produced. Since all variables in XSLT are static, the
correct approach was to call a named template recursively.
First I calculate the maximum number of rows by creating a variable that
contains an XML fragment holding the set of <optionListx> elements sorted in
descending order by the count of the number of <option> children.:
<xsl:template match="free-xml">
<xsl:variable name="list-with-max-option-children">
<xsl:for-each select="*">
<xsl:sort select="count(option)" data-type="number" order="descending"
/>
<xsl:copy-of select="." />
</xsl:for-each>
</xsl:variable>
... The balance of the template goes here ...
</xsl:template >
Then, by taking the count of the <option> children in the first <optionListx>
element in the sorted fragment, I know the maximum number of rows to be
produced and we begin the recursive calls to the template that will produce the
rows of your table.
<xsl:template match="free-xml">
<xsl:variable name="list-with-max-option-children">
<xsl:for-each select="*">
<xsl:sort select="count(option)" data-type="number" order="descending"
/>
<xsl:copy-of select="." />
</xsl:for-each>
</xsl:variable>
<table>
<xsl:call-template name="table-row">
<xsl:with-param name="max-rows"
select="count($list-with-max-option-children/*[1]/option)" />
<xsl:with-param name="current-row" select="1" />
</xsl:call-template>
</table>
</xsl:template>
Note that we pass two parameters, "max-rows" which sets the stopping point for
the recursive calls to the template named "table-rows", and "current-row" that
selects the position of the set of <option> elements whose values will be
placed in the <td> elements in the row.
Most of the work is done in the template named "table-row":
<xsl:template name="table-row">
<xsl:param name="max-rows" />
<xsl:param name="current-row" />
... The first thing the template does is check to see if the maximum
number of rows has been reached, it aborts if this is true. ...
<xsl:if test="$current-row <= $max-rows">
<tr>
<xsl:choose>
<xsl:when test="/enquiry-data/free-xml/*[1]/option[$current-row]">
<td><xsl:value-of
select="/enquiry-data/free-xml/*[1]/option[$current-row]" /></td>
</xsl:when>
<xsl:otherwise><td /></xsl:otherwise>
</xsl:choose>
.. Most of the template looks like this. There are known to be exactly seven
columns (which translates to seven <td> elements in each row, so the bulk of
the template consists of <xsl:choose> elements like this, one for each column.
The value in the first set of square brackets here,
"*[1]/option[$current-row]" increments for each <xsl:choose> so you get values
from 1 through 7.
The test looks to see if there is an <option> element at that position, and if
so, it places its value in the <td>, otherwise an empty <td /> is emitted.
After processing all <xsl:choose> statments we make a recursive call to the
same template. ...
</tr>
<xsl:call-template name="table-row">
<xsl:with-param name="max-rows" select="$max-rows" />
<xsl:with-param name="current-row" select="$current-row + 1" />
</xsl:call-template>
... The trick here is to add one to the value of $current-row and pass it
along to the next call of the template. Although this may look like we are
changing the value of a variable (not permitted in XSLT), we really aren't. We
are creating a new variable with the same name in a different context.
I've been looking for a new job this week so I've had plenty of time on my
hands to work your problem. Not everyone can spend this kind of time on a
challenge, so the next time you have one, you may or may not get this much
attention. Good luck.
The complete stylesheet:
================
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="enquiry-data">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="free-xml">
<xsl:variable name="list-with-max-option-children">
<xsl:for-each select="*">
<xsl:sort select="count(option)" data-type="number" order="descending"
/>
<xsl:copy-of select="." />
</xsl:for-each>
</xsl:variable>
<table>
<xsl:call-template name="table-row">
<xsl:with-param name="max-rows"
select="count($list-with-max-option-children/*[1]/option)" />
<xsl:with-param name="current-row" select="1" />
</xsl:call-template>
</table>
</xsl:template>
<xsl:template name="table-row">
<xsl:param name="max-rows" />
<xsl:param name="current-row" />
<xsl:if test="$current-row <= $max-rows">
<tr>
<xsl:choose>
<xsl:when test="/enquiry-data/free-xml/*[1]/option[$current-row]">
<td><xsl:value-of
select="/enquiry-data/free-xml/*[1]/option[$current-row]" /></td>
</xsl:when>
<xsl:otherwise><td /></xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="/free-xml/*[2]/option[$current-row]">
<td><xsl:value-of
select="/enquiry-data/free-xml/*[2]/option[$current-row]" /></td>
</xsl:when>
<xsl:otherwise><td /></xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="/enquiry-data/free-xml/*[3]/option[$current-row]">
<td><xsl:value-of
select="/enquiry-data/free-xml/*[3]/option[$current-row]" /></td>
</xsl:when>
<xsl:otherwise><td /></xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="/enquiry-data/free-xml/*[4]/option[$current-row]">
<td><xsl:value-of
select="/enquiry-data/free-xml/*[4]/option[$current-row]" /></td>
</xsl:when>
<xsl:otherwise><td /></xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="/enquiry-data/free-xml/*[5]/option[$current-row]">
<td><xsl:value-of
select="/enquiry-data/free-xml/*[5]/option[$current-row]" /></td>
</xsl:when>
<xsl:otherwise><td /></xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="/enquiry-data/free-xml/*[6]/option[$current-row]">
<td><xsl:value-of
select="/enquiry-data/free-xml/*[6]/option[$current-row]" /></td>
</xsl:when>
<xsl:otherwise><td /></xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="/enquiry-data/free-xml/*[7]/option[$current-row]">
<td><xsl:value-of
select="/enquiry-data/free-xml/*[7]/option[$current-row]" /></td>
</xsl:when>
<xsl:otherwise><td /></xsl:otherwise>
</xsl:choose>
</tr>
<xsl:call-template name="table-row">
<xsl:with-param name="max-rows" select="$max-rows" />
<xsl:with-param name="current-row" select="$current-row + 1" />
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
--
Charles Knell
cknell(_at_)onebox(_dot_)com - email
--~------------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--