xsl-list
[Top] [All Lists]

[xsl] Feedback on grouping solution

2019-10-26 12:03:05
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
--~--
<Prev in Thread] Current Thread [Next in Thread>