Subject: RE: [xsl] Calculating cumulative values - Abel's solution From: "Simon Shutter" <simon@xxxxxxxxxxx> Date: Fri, 31 Aug 2007 09:56:42 -0700 |
Abel, The example input I provided in my original question was simplified so that I could convey the problem more clearly and so that I would have a better chance of understanding the solutions offered. In retrospect, I can see why you guys always ask for a 'real' data set when helping us newbies out :). Anyhow, with that off my chest I was able to adapt your stylesheet to the 'real' data (SVG). The question I have now is how to replicate the top three levels in the hierarchy to the output. Do I have to change the pattern match on the root node? Thanks, Simon Here's the 'real' data: <g id="theroot" xmlns:myns="http://www.acme.com/myns"> <g id="groupA"> <svg x="10" y="10" width="1000" height="1000" viewBox="0 0 1000 1000"> <g transform="scale(1,1)"> <rect x="1" myns:y1="2" width="100" height="100" fill="red" /> <rect x="1" myns:y1="3" width="100" height="100" fill="red" /> <rect x="1" myns:y1="0" width="100" height="100" fill="red" /> <rect x="1" myns:y1="2" width="100" height="100" fill="red" /> <rect x="1" myns:y1="2" width="100" height="100" fill="red" /> <rect x="2" myns:y1="3" width="100" height="100" fill="red" /> <rect x="2" myns:y1="0" width="100" height="100" fill="red" /> <rect x="2" myns:y1="2" width="100" height="100" fill="red" /> <rect x="3" myns:y1="2" width="100" height="100" fill="red" /> <rect x="3" myns:y1="3" width="100" height="100" fill="red" /> <rect x="3" myns:y1="1" width="100" height="100" fill="red" /> <rect x="3" myns:y1="2" width="100" height="100" fill="red" /> <rect x="3" myns:y1="2" width="100" height="100" fill="red" /> </g> </svg> </g> <g id="groupB"> <svg x="10" y="1010" width="1000" height="1000" viewBox="0 0 1000 1000"> <g transform="scale(1,1)"> <rect x="1" myns:y1="2" width="100" height="100" fill="red" /> <rect x="1" myns:y1="3" width="100" height="100" fill="red" /> <rect x="1" myns:y1="0" width="100" height="100" fill="red" /> <rect x="1" myns:y1="2" width="100" height="100" fill="red" /> <rect x="2" myns:y1="2" width="100" height="100" fill="red" /> <rect x="3" myns:y1="2" width="100" height="100" fill="red" /> <rect x="3" myns:y1="2" width="100" height="100" fill="red" /> <rect x="3" myns:y1="2" width="100" height="100" fill="red" /> </g> </svg> </g> <g id="groupC"> <svg x="10" y="2010" width="1000" height="1000" viewBox="0 0 1000 1000"> <g transform="scale(1,1)"> <rect x="1" myns:y1="2" width="100" height="100" fill="red" /> <rect x="1" myns:y1="3" width="100" height="100" fill="red" /> <rect x="1" myns:y1="2" width="100" height="100" fill="red" /> <rect x="2" myns:y1="3" width="100" height="100" fill="red" /> <rect x="2" myns:y1="0" width="100" height="100" fill="red" /> <rect x="2" myns:y1="2" width="100" height="100" fill="red" /> <rect x="3" myns:y1="3" width="100" height="100" fill="red" /> </g> </svg> </g> </g> Here's how I adapted your solution: <?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" xmlns:myns="http://www.acme.com/myns"> <xsl:output indent="yes" /> <xsl:template match="/"> <!-- mini pipeline: put rects into a variable and process them --> <xsl:variable name="rects"> <xsl:apply-templates select="g/g[1]/svg[1]/g[1]/rect[1]" mode="aggregate"> <xsl:with-param name="calc" tunnel="yes"> <for x="1" y2="2" y3="2"/> </xsl:with-param> </xsl:apply-templates> </xsl:variable> <!-- apply g with pre-processed rects --> <xsl:apply-templates select="g/g/svg/g"> <xsl:with-param name="rects" select="$rects" /> </xsl:apply-templates> </xsl:template> <!-- get calculated values --> <xsl:template match="rect" use-when="1"> <xsl:copy> <xsl:copy-of select="@x | @myns:y1 | @y2 | @y3 | @width | @height | @fill" /> </xsl:copy> </xsl:template> <!-- apply the calculated rects belonging to the current g --> <xsl:template match="g/g/svg/g"> <xsl:param name="rects" /> <xsl:copy> <xsl:copy-of select="@*" /> <xsl:apply-templates select="$rects/rect[@parent-id = generate-id(current())]" /> </xsl:copy> </xsl:template> <!-- calculation of the rects (needs some cleaning) --> <xsl:template match="rect" mode="aggregate"> <xsl:param name="calc" tunnel="yes" /> <!-- helper variables --> <xsl:variable name="next-rect" select="following::rect[1]" /> <xsl:variable name="next-x" select="$next-rect/@x" /> <xsl:variable name="next-y" select="($next-rect/@myns:y1, 0)[1]" as="xs:integer" /> <!-- the $calc block contains the current calculation, index is based on the @x value (i.e., one calc block per @x value --> <xsl:variable name="current-calc" select="$calc/for[@x = current()/@x]" /> <xsl:variable name="next-calc" select="$calc/for[@x = $next-x]" /> <xsl:variable name="next-y3" select="xs:integer(($next-calc/@y3, 0)[1])" as="xs:integer" /> <!-- holds 1 in normal situation, 2 when a new x value arrives --> <xsl:variable name="new-x-value" select="number(@x = $next-x) + 1" /> <xsl:copy> <xsl:copy-of select="@*" /> <xsl:attribute name="y2" select="$current-calc/@y2" /> <xsl:attribute name="y3" select="$current-calc/@y3" /> <xsl:attribute name="parent-id" select="generate-id(parent::node())" /> <!-- copy is for debugging purposes, remove to prevent bloating --> <xsl:copy-of select="$calc" /> </xsl:copy> <xsl:variable name="var"> </xsl:variable> <xsl:apply-templates select="following::rect[1]" mode="#current" > <xsl:with-param name="calc" tunnel="yes"> <xsl:variable name="new-for"> <xsl:variable name="source-y2" select="(0, $next-rect/@myns:y1)[$new-x-value]" as="xs:integer" /> <xsl:variable name="prev-y2" select="($next-rect/@myns:y1, $current-calc/@y2)[$new-x-value]" as="xs:integer" /> <xsl:variable name="sum-y3" select="$next-y3 + $next-y" /> <for x="{$next-rect/@x}" y2="{$source-y2 + $prev-y2}" y3="{$sum-y3}" /> </xsl:variable> <!-- select the new one only for the current x --> <xsl:for-each select="distinct-values(($calc/for/@x, $next-x))"> <xsl:copy-of select=" ($new-for/for[@x = current()], $calc/for[@x = current()])[1]" /> </xsl:for-each> </xsl:with-param> </xsl:apply-templates> </xsl:template> </xsl:stylesheet> And here's what I am outputting: <?xml version="1.0" encoding="UTF-8"?> <g xmlns:myns="http://www.acme.com/myns" transform="scale(1,1)"> <rect x="1" myns:y1="2" width="100" height="100" fill="red" y2="2" y3="2"/> <rect x="1" myns:y1="3" width="100" height="100" fill="red" y2="5" y3="5"/> <rect x="1" myns:y1="0" width="100" height="100" fill="red" y2="5" y3="5"/> <rect x="1" myns:y1="2" width="100" height="100" fill="red" y2="7" y3="7"/> <rect x="1" myns:y1="2" width="100" height="100" fill="red" y2="9" y3="9"/> <rect x="2" myns:y1="3" width="100" height="100" fill="red" y2="3" y3="3"/> <rect x="2" myns:y1="0" width="100" height="100" fill="red" y2="3" y3="3"/> <rect x="2" myns:y1="2" width="100" height="100" fill="red" y2="5" y3="5"/> <rect x="3" myns:y1="2" width="100" height="100" fill="red" y2="2" y3="2"/> <rect x="3" myns:y1="3" width="100" height="100" fill="red" y2="5" y3="5"/> <rect x="3" myns:y1="1" width="100" height="100" fill="red" y2="6" y3="6"/> <rect x="3" myns:y1="2" width="100" height="100" fill="red" y2="8" y3="8"/> <rect x="3" myns:y1="2" width="100" height="100" fill="red" y2="10" y3="10"/> </g> <g xmlns:myns="http://www.acme.com/myns" transform="scale(1,1)"> <rect x="1" myns:y1="2" width="100" height="100" fill="red" y2="2" y3="11"/> <rect x="1" myns:y1="3" width="100" height="100" fill="red" y2="5" y3="14"/> <rect x="1" myns:y1="0" width="100" height="100" fill="red" y2="5" y3="14"/> <rect x="1" myns:y1="2" width="100" height="100" fill="red" y2="7" y3="16"/> <rect x="2" myns:y1="2" width="100" height="100" fill="red" y2="2" y3="7"/> <rect x="3" myns:y1="2" width="100" height="100" fill="red" y2="2" y3="12"/> <rect x="3" myns:y1="2" width="100" height="100" fill="red" y2="4" y3="14"/> <rect x="3" myns:y1="2" width="100" height="100" fill="red" y2="6" y3="16"/> </g> <g xmlns:myns="http://www.acme.com/myns" transform="scale(1,1)"> <rect x="1" myns:y1="2" width="100" height="100" fill="red" y2="2" y3="18"/> <rect x="1" myns:y1="3" width="100" height="100" fill="red" y2="5" y3="21"/> <rect x="1" myns:y1="2" width="100" height="100" fill="red" y2="7" y3="23"/> <rect x="2" myns:y1="3" width="100" height="100" fill="red" y2="3" y3="10"/> <rect x="2" myns:y1="0" width="100" height="100" fill="red" y2="3" y3="10"/> <rect x="2" myns:y1="2" width="100" height="100" fill="red" y2="5" y3="12"/> <rect x="3" myns:y1="3" width="100" height="100" fill="red" y2="3" y3="19"/> </g>
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Re: [xsl] Calculating cumulative va, Abel Braaksma | Thread | Re: [xsl] Calculating cumulative va, Abel Braaksma |
Re: [xsl] html as input to xslt, B Tommie Usdin | Date | Re: [xsl] Calculating cumulative va, Abel Braaksma |
Month |