Hi All,
I have the following input:
<?xml version="1.0" encoding="UTF-8"?>
<procedure>
<title/>
<step>
<para/>
<important/>
<figure/>
<figure/>
</step>
<note/>
<step>
<para/>
<figure/>
<figure/>
<note/>
<figure/>
</step>
<step>
<para/>
<figure/>
<figure/>
</step>
</procedure>
I need to process the <step> child elements so that the <figure> elements
are always on the "right" (even-numbered position) in the output. Immediate
children of the <procedure> do not factor into the odd/even sequence.
The first child of each group of adjacent <step> elements starts a new
odd/even series. To ensure that the each <figure> is in an even-numbered
position, I want to insert a <spacer> element where it is required.
Here is the desired output for the sample input (comments added for
clarity):
<?xml version="1.0" encoding="UTF-8"?>
<procedure>
<title/>
<para/> <!-- odd -->
<important/> <!-- even -->
<spacer/> <!-- odd -->
<figure/> <!-- even -->
<spacer/> <!-- odd -->
<figure/> <!-- even -->
<note/>
<para/> <!-- odd -->
<figure/> <!-- even -->
<spacer/> <!-- odd -->
<figure/> <!-- even -->
<note/> <!-- odd -->
<figure/> <!-- even -->
<para/> <!-- odd -->
<figure/> <!-- even -->
<spacer/> <!-- odd -->
<figure/> <!-- even -->
</procedure>
Here is my stylesheet. My basic question is: is there a better or more
efficient way to do this? I really want to master grouping because it comes
up in a lot of my tasks. Thank you for any input or criticism.
<?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="local-name(.)">
<xsl:choose>
<xsl:when test="current-group()[1][not(self::step)]">
<!-- Single element. -->
<xsl:apply-templates select="current-group()[1]"/>
</xsl:when>
<xsl:otherwise>
<!-- step group, process the children. -->
<xsl:variable name="elements"
select="current-group()/*"/>
<xsl:message select="$elements"/>
<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: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]">
<xsl:choose>
<!-- See where the figure is going to fall in the
output. -->
<xsl:when test="$positionInOutput mod 2 != 0">
<!-- A spacer to force the figure to the right. -->
<spacer/>
<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: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: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>
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
--~--