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
cell
elements at positions 1 and 2 in source.xml. Their total value ofaid:ccols
attributes is 4 (3 1), therefore their resulantth
elements should be wrapped with an opening and closingtr
tag.Consider
cell
elements in source.xml at positions 3,4, and 5. Their total value ofaid:ccols
attributes is 4 (2 1 1) therefore their resulantth
elements should be wrapped with an opening and closingtr
tag.Consider the
cell
element in source.xml at positions 6. Itsaid:ccols
value already totals 4 therefore its resultantth
element should be wrapped with an opening and closingtr
tag.
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.