Hi Dimitre,
Thanks for the follow up. Yes, the children of adjacent step elements have to
be treated as one group and that lead me to discover another possibility: the
first para in each step in the group has to start on the "left" (an
odd-numbered position in the output group). I modified the test input so that
the first para in the last step would require a spacer.
<?xml version="1.0" encoding="UTF-8"?>
<procedure>
<title/>
<step>
<para/>
<important/>
<figure/>
<figure/>
</step>
<note/>
<note/>
<step>
<para/>
<figure/>
<figure/>
<note/>
<figure/>
<caution/>
</step>
<step>
<para/> <!-- will need a spacer -->
<figure/>
<figure/>
</step>
</procedure>
Here is the updated stylesheet:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs"
version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="/procedure">
<procedure>
<!-- Group the children of the procedure, keeping adjacent steps
together. -->
<xsl:for-each-group select="child::*"
group-adjacent="boolean(self::step)">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<!-- step group, process the children. -->
<xsl:variable name="elements"
select="current-group()/*"/>
<xsl:call-template name="step-element">
<xsl:with-param name="elements" select="$elements"/>
<xsl:with-param name="positionInGroup" select="1"/>
<xsl:with-param name="positionInOutput" select="1"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</procedure>
</xsl:template>
<xsl:template name="step-element">
<xsl:param name="elements"/>
<xsl:param name="positionInGroup"/>
<xsl:param name="positionInOutput"/>
<xsl:variable name="currentElement"
select="$elements[$positionInGroup]"/>
<xsl:choose>
<xsl:when test="$currentElement[self::figure or self::para]">
<xsl:choose>
<!-- See where the figure or first para is going to fall in
the output. -->
<xsl:when test="($currentElement[self::figure] and
$positionInOutput mod 2 != 0) or
($currentElement[self::para] and $positionInOutput mod
2 = 0 and not($currentElement/preceding-sibling::*))">
<!-- A spacer to force the figure to the right
or the first para in a step to the left. -->
<spacer/> <xsl:comment select="$positionInOutput"/>
<xsl:call-template name="step-element">
<xsl:with-param name="elements" select="$elements"/>
<xsl:with-param name="positionInGroup"
select="$positionInGroup"/>
<xsl:with-param name="positionInOutput"
select="$positionInOutput + 1"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="$currentElement"/>
<xsl:comment select="$positionInOutput"/>
<xsl:if test="$elements[$positionInGroup + 1]">
<xsl:call-template name="step-element">
<xsl:with-param name="elements"
select="$elements"/>
<xsl:with-param name="positionInGroup"
select="$positionInGroup + 1"/>
<xsl:with-param name="positionInOutput"
select="$positionInOutput + 1"/>
</xsl:call-template>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="$currentElement"/> <xsl:comment
select="$positionInOutput"/>
<xsl:if test="$elements[$positionInGroup + 1]">
<xsl:call-template name="step-element">
<xsl:with-param name="elements" select="$elements"/>
<xsl:with-param name="positionInGroup"
select="$positionInGroup + 1"/>
<xsl:with-param name="positionInOutput"
select="$positionInOutput + 1"/>
</xsl:call-template>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Identity transform -->
<xsl:template match="element()">
<xsl:copy>
<xsl:apply-templates select="@*, node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Here is the output with comments indicating each element's position within the
group in the output.
<?xml version="1.0" encoding="UTF-8"?>
<procedure>
<title/>
<para/> <!--1-->
<important/> <!--2-->
<spacer/> <!--3-->
<figure/> <!--4-->
<spacer/> <!--5-->
<figure/> <!--6-->
<note/>
<note/>
<para/> <!--1-->
<figure/> <!--2-->
<spacer/> <!--3-->
<figure/> <!--4-->
<note/> <!--5-->
<figure/> <!--6-->
<caution/> <!--7-->
<spacer/> <!--8-->
<para/> <!--9-->
<figure/> <!--10-->
<spacer/> <!--11-->
<figure/> <!--12-->
</procedure>
Although the two-pass solution is more compact and XSLT 1.0-compatible, it has
been useful for me to work through and try to understand the recursion I have
to use. Thank you to all who contributed. This is a great list!
Rick
--~----------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
EasyUnsubscribe: http://lists.mulberrytech.com/unsub/xsl-list/1167547
or by email: xsl-list-unsub(_at_)lists(_dot_)mulberrytech(_dot_)com
--~--