When transforming the following XML instance;
source.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<indd xmlns:aid="http://ns.adobe.com/AdobeInDesign/4.0/" xmlns:aid5="http://ns.adobe.com/AdobeInDesign/5.0/">
<article>
<table aid5:tablestyle="my-table" aid:trows="10" aid:tcols="4">
<cell aid:theader="" aid:ccols="3">Head A</cell>
<cell aid:theader="" aid:ccols="1">Head B</cell>
<cell aid:ccols="2">A</cell>
<cell aid:ccols="1">B</cell>
<cell aid:ccols="1">C</cell>
<cell aid:ccols="4"></cell>
<cell aid:ccols="1">E</cell>
<cell aid:ccols="1">F</cell>
<cell aid:ccols="1">G</cell>
<cell aid:ccols="1">H</cell>
<cell aid:ccols="1">I</cell>
<cell aid:ccols="1">J</cell>
<cell aid:ccols="1">K</cell>
<cell aid:ccols="1">L</cell>
<cell aid:ccols="1">M</cell>
<cell aid:ccols="1">N</cell>
<cell aid:ccols="1">O</cell>
<cell aid:ccols="1">P</cell>
<cell aid:ccols="1">Q</cell>
<cell aid:ccols="1">R</cell>
<cell aid:ccols="1">S</cell>
<cell aid:ccols="1">T</cell>
<cell aid:ccols="1">U</cell>
<cell aid:ccols="1">V</cell>
<cell aid:ccols="1">W</cell>
<cell aid:ccols="1">X</cell>
<cell aid:ccols="1">Y</cell>
<cell aid:ccols="3">Z</cell>
</table>
</article>
</indd>
using the following XSLT (1.0);
transform.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:aid="http://ns.adobe.com/AdobeInDesign/4.0/"
xmlns:aid5="http://ns.adobe.com/AdobeInDesign/5.0/"
exclude-result-prefixes="aid aid5"
version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="indd/article/table[@aid5:tablestyle='my-table']">
<table>
<xsl:attribute name="class">
<xsl:value-of select="@aid5:tablestyle"/>
</xsl:attribute>
<xsl:for-each select="cell">
<xsl:choose>
<xsl:when test="@aid:theader=''">
<th>
<xsl:attribute name="colspan">
<xsl:value-of select="@aid:ccols"/>
</xsl:attribute>
<xsl:value-of select="."/>
</th>
</xsl:when>
<xsl:otherwise>
<td>
<xsl:attribute name="colspan">
<xsl:value-of select="@aid:ccols"/>
</xsl:attribute>
<xsl:value-of select="."/>
</td>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
It produces the following output:
result.xml
<?xml version="1.0" encoding="UTF-8"?>
<table >
<th colspan="3">Head A</th>
<th colspan="1">Head B</th>
<td colspan="2">A</td>
<td colspan="1">B</td>
<td colspan="1">C</td>
<td colspan="4"/>
<td colspan="1">E</td>
<td colspan="1">F</td>
<td colspan="1">G</td>
<td colspan="1">H</td>
<td colspan="1">I</td>
<td colspan="1">J</td>
<td colspan="1">K</td>
<td colspan="1">L</td>
<td colspan="1">M</td>
<td colspan="1">N</td>
<td colspan="1">O</td>
<td colspan="1">P</td>
<td colspan="1">Q</td>
<td colspan="1">R</td>
<td colspan="1">S</td>
<td colspan="1">T</td>
<td colspan="1">U</td>
<td colspan="1">V</td>
<td colspan="1">W</td>
<td colspan="1">X</td>
<td colspan="1">Y</td>
<td colspan="3">Z</td>
</table>
Desired Result
However, my requirement is the transform source.xml to produce the following:
wanted.xml
<?xml version="1.0" encoding="UTF-8"?>
<table >
<tr>
<th colspan="3">Head A</th>
<th colspan="1">Head B</th>
</tr>
<tr>
<td colspan="2">A</td>
<td colspan="1">B</td>
<td colspan="1">C</td>
</tr>
<tr>
<td colspan="4"/>
</tr>
<tr>
<td colspan="1">E</td>
<td colspan="1">F</td>
<td colspan="1">G</td>
<td colspan="1">H</td>
</tr>
<tr>
<td colspan="1">I</td>
<td colspan="1">J</td>
<td colspan="1">K</td>
<td colspan="1">L</td>
</tr>
<tr>
<td colspan="1">M</td>
<td colspan="1">N</td>
<td colspan="1">O</td>
<td colspan="1">P</td>
</tr>
<tr>
<td colspan="1">Q</td>
<td colspan="1">R</td>
<td colspan="1">S</td>
<td colspan="1">T</td>
</tr>
<tr>
<td colspan="1">U</td>
<td colspan="1">V</td>
<td colspan="1">W</td>
<td colspan="1">X</td>
</tr>
<tr>
<td colspan="1">Y</td>
<td colspan="3">Z</td>
</tr>
</table>
Currently transform.xsl does not transform source.xml to include the necessary tr elements that are present in wanted.xml.
Question
Is it possible to use XSLT (1.0) to include the necessary tr elements as shown in wanted.xml?
As you can see, the values of the aid:ccols attributes for each cell element that is present in source.xml could be utilized to inform the transformation as to when the resultant th or td element(s) should be wrapped in tr elements. Essentially it's when consecutive aid:ccols values total 4 as per the value of the table elements aid:tcols="4" attribute in source.xml.
For example:
Consider the first two
cellelements at positions 1 and 2 in source.xml. Their total value ofaid:ccolsattributes is 4 (3 1), therefore their resulantthelements should be wrapped with an opening and closingtrtag.Consider
cellelements in source.xml at positions 3,4, and 5. Their total value ofaid:ccolsattributes is 4 (2 1 1) therefore their resulantthelements should be wrapped with an opening and closingtrtag.Consider the
cellelement in source.xml at positions 6. Itsaid:ccolsvalue already totals 4 therefore its resultantthelement should be wrapped with an opening and closingtrtag.
CodePudding user response:
If I understand this correctly, you want to do something like:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:aid5="http://ns.adobe.com/AdobeInDesign/5.0/"
xmlns:aid="http://ns.adobe.com/AdobeInDesign/4.0/"
exclude-result-prefixes="aid5 aid">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="table">
<table >
<tr>
<xsl:for-each select="cell[@aid:theader]">
<th colspan="{@aid:ccols}">
<xsl:value-of select="."/>
</th>
</xsl:for-each>
</tr>
<xsl:call-template name="body">
<xsl:with-param name="cells" select="cell[not(@aid:theader)]"/>
<xsl:with-param name="target-width" select="@aid:tcols"/>
</xsl:call-template>
</table>
</xsl:template>
<xsl:template name="body">
<xsl:param name="cells"/>
<xsl:param name="target-width"/>
<xsl:param name="row" select="/.."/>
<xsl:param name="width" select="0"/>
<xsl:choose>
<xsl:when test="$width >= $target-width">
<tr>
<xsl:for-each select="$row">
<td colspan="{@aid:ccols}">
<xsl:value-of select="."/>
</td>
</xsl:for-each>
</tr>
<!-- recursive call -->
<xsl:call-template name="body">
<xsl:with-param name="cells" select="$cells"/>
<xsl:with-param name="target-width" select="$target-width"/>
<xsl:with-param name="row" select="/.."/>
<xsl:with-param name="width" select="0"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="$cells">
<xsl:variable name="cell" select="$cells[1]" />
<xsl:call-template name="body">
<xsl:with-param name="cells" select="$cells[position() > 1]"/>
<xsl:with-param name="target-width" select="$target-width"/>
<xsl:with-param name="row" select="$row | $cell"/>
<xsl:with-param name="width" select="$width $cell/@aid:ccols"/>
</xsl:call-template>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Another possible approach is a technique known as "sibling recursion" (look it up). Though the basic principle is same.
