[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message] Re: Feedback on grouping solution
> Now waiting for Dimitre posting a less "fancy" > but equally compact XSLT 1 solution :) The following is a 48-lines XSLT 2.0 solution (2 passes -- equivalent XSLT 1.0 solution is easy to produce but will need the vendor:node-set() extension function). Martin's XSLT 3.0 solution is 43 lines when <xsl:stylesheet> and <xsl:output> are added. So the difference in number of lines is not big -- 12% and I believe the XSLT 2 solution below is less complex and more easily understandable. Maybe I am biased, but I personally believe that it is better to use the standard XPath 3 functions fold-left() and fold-right() in the spirit of functional programming. <xsl:iterate> instead helps people avoid thinking using the concepts of functional programming. Also, its definition is so complex that I personally needed more than an hour to find out / construct what cases of its usage are possible and which are mutually exclusive. Here is the transformation: <xsl:stylesheet version="2.0" xmlns:xsl=" http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:variable name="vPass1Result"><xsl:apply-templates select="/*"/></xsl:variable> <xsl:template match="node()|@*" mode="#default pass2"> <xsl:copy> <xsl:apply-templates select="node()|(@* except @stepChild)" mode="#current"/> </xsl:copy> </xsl:template> <xsl:template match="/"> <xsl:apply-templates select="$vPass1Result/*" mode="pass2"/> </xsl:template> <xsl:template match="step"><xsl:apply-templates/></xsl:template> <xsl:template match="step/*"> <xsl:copy> <xsl:apply-templates select="@*"/> <xsl:attribute name="stepChild"> <xsl:number level="any" count="/*/step/*"/> </xsl:attribute> <xsl:apply-templates select="node()"/> </xsl:copy> </xsl:template> <xsl:template match="/*" mode="pass2"> <xsl:copy> <xsl:apply-templates select="*[1]" mode="pass2"/> </xsl:copy> </xsl:template> <xsl:template match="/*/*" mode="pass2"> <xsl:param name="pAdjustments" select="0"/> <xsl:variable name="vNeedsAdjustment" select="self::figure and (count(preceding-sibling::*[@stepChild]) +1 + $pAdjustments) mod 2 = 1"/> <xsl:if test="$vNeedsAdjustment"> <spacer/> </xsl:if> <xsl:next-match/> <xsl:apply-templates select="following-sibling::*[1]" mode="pass2"> <xsl:with-param name="pAdjustments" select="$pAdjustments + (if($vNeedsAdjustment) then 1 else 0)"/> </xsl:apply-templates> </xsl:template> </xsl:stylesheet> Cheers, Dimitre On Sat, Oct 26, 2019 at 12:06 PM Martin Honnen martin.honnen@xxxxxx < xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote: > On 26.10.2019 19:03, Rick Quatro rick@xxxxxxxxxxxxxx wrote: > > > 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 my stylesheet. My basic question is: is there a better or more > > efficient way to do this? > > I think with XSLT 3 it is possible to use xsl:iterate on the child > elements of the adjacent steps found by grouping: > > <xsl:mode on-no-match="shallow-copy"/> > > <xsl:template match="procedure"> > <xsl:copy> > <xsl:for-each-group select="*" > group-adjacent="boolean(self::step)"> > <xsl:choose> > <xsl:when test="current-grouping-key()"> > <xsl:iterate select="current-group()/*"> > <xsl:param name="position-in-output" > select="1"/> > <xsl:apply-templates select="."> > <xsl:with-param > name="position-in-output" select="$position-in-output"/> > </xsl:apply-templates> > <xsl:next-iteration> > <xsl:with-param name="position-in-output" > select="if (self::figure and > $position-in-output mod 2 = 1) > then $position-in-output + 2 > else $position-in-output + > 1"/> > </xsl:next-iteration> > </xsl:iterate> > </xsl:when> > <xsl:otherwise> > <xsl:apply-templates select="current-group()"/> > </xsl:otherwise> > </xsl:choose> > </xsl:for-each-group> > </xsl:copy> > </xsl:template> > > <xsl:template match="step/figure"> > <xsl:param name="position-in-output"/> > <xsl:if test="$position-in-output mod 2 = 1"> > <spacer/> > </xsl:if> > <xsl:next-match/> > </xsl:template> > > > > Now waiting for Dimitre posting a less "fancy" but equally compact XSLT > 1 solution :) > > -- Cheers, Dimitre Novatchev --------------------------------------- Truly great madness cannot be achieved without significant intelligence. --------------------------------------- To invent, you need a good imagination and a pile of junk ------------------------------------- Never fight an inanimate object ------------------------------------- To avoid situations in which you might make mistakes may be the biggest mistake of all ------------------------------------ Quality means doing it right when no one is looking. ------------------------------------- You've achieved success in your field when you don't know whether what you're doing is work or play ------------------------------------- To achieve the impossible dream, try going to sleep. ------------------------------------- Facts do not cease to exist because they are ignored. ------------------------------------- Typing monkeys will write all Shakespeare's works in 200yrs.Will they write all patents, too? :) ------------------------------------- Sanity is madness put to good use. ------------------------------------- I finally figured out the only reason to be alive is to enjoy it.
|
PURCHASE STYLUS STUDIO ONLINE TODAY!Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced! Download The World's Best XML IDE!Accelerate XML development with our award-winning XML IDE - Download a free trial today! Subscribe in XML format
|