[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

Re: Feedback on grouping solution

Subject: Re: Feedback on grouping solution
From: "Rick Quatro rick@xxxxxxxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Mon, 28 Oct 2019 12:52:19 -0000
Re:  Feedback on grouping solution
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

Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.