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[(_at_)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[(_at_)x = current()/@x]"
/>
<xsl:variable name="next-calc" select="$calc/for[(_at_)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[(_at_)x = current()],
$calc/for[(_at_)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>
--~------------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--