Subject: Re: [xsl] Feedback on grouping solution From: "Rick Quatro rick@xxxxxxxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> Date: Mon, 28 Oct 2019 12:52:19 -0000 |
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 |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Re: [xsl] Feedback on grouping solu, Dimitre Novatchev dn | Thread | |
Re: [xsl] Feedback on grouping solu, Dimitre Novatchev dn | Date | |
Month |