grouping - XSLT group by half hour -
given xml:
<root> <row> <time>08:00</time> <sales>800</sales> </row> <row> <time>08:15</time> <sales>815</sales> </row> <row> <time>08:30</time> <sales>830</sales> </row> <row> <time>08:45</time> <sales>845</sales> </row> <row> <time>11:00</time> <sales>1100</sales> </row> <row> <time>11:45</time> <sales>1145</sales> </row> <row> <time>14:15</time> <sales>1415</sales> </row> <row> <time>14:30</time> <sales>1430</sales> </row> </root> i trying find way xslt transform summarizing sales 30 minute intervals. can summarize hourly intervals 60 minutes using muenchian method, cannot use 30 minute since need custom function (but cannot use xslt 2.0, nor .net's custom functions). please help!
the expected output this:
30 minute 08:00 $1600 08:30 $1675 11:00 $1100 11:30 $1145 14:00 $1415 14:30 $1430
solution 1.
this transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform"> <xsl:output method="text"/> <xsl:key name="krowsinhalfhour" match= "row[not((substring-after(time,':')+30) mod 30 = 0)]" use="generate-id( preceding-sibling::row [60*substring-before(time,':') + substring-after(time,':') >= 60*substring-before(current()/time,':') + substring-after(current()/time,':') - substring-after(current()/time,':') mod 30 ] [1] ) "/> <xsl:template match= "row[(substring-after(time,':')+30) mod 30 = 0 or not( 60*substring-before(preceding-sibling::row[1]/time,':') + substring-after(preceding-sibling::row[1]/time,':') >= 60*substring-before(time,':') + substring-after(time,':') - substring-after(time,':') mod 30 ) ] "> <xsl:variable name="vprevstartmins" select= "60*substring-before(time,':') + substring-after(time,':') - substring-after(time,':') mod 30 "/> <xsl:value-of select= "concat('
',floor($vprevstartmins div 60), ':', concat(substring('0',($vprevstartmins mod 60 >0)+1), $vprevstartmins mod 60 ) ) "/> <xsl:text> $</xsl:text> <xsl:value-of select= "sum(sales | key('krowsinhalfhour',generate-id())/sales)"/> </xsl:template> <xsl:template match="text()"/> </xsl:stylesheet> when applied on provided xml document:
<root> <row> <time>08:00</time> <sales>800</sales> </row> <row> <time>08:15</time> <sales>815</sales> </row> <row> <time>08:30</time> <sales>830</sales> </row> <row> <time>08:45</time> <sales>845</sales> </row> <row> <time>11:00</time> <sales>1100</sales> </row> <row> <time>11:45</time> <sales>1145</sales> </row> <row> <time>14:15</time> <sales>1415</sales> </row> <row> <time>14:30</time> <sales>1430</sales> </row> </root> produces wanted, correct result:
8:00 $1615 8:30 $1675 11:00 $1100 11:30 $1145 14:00 $1415 14:30 $1430 solution 2:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform" xmlns:my="my:my" > <xsl:output method="text"/> <xsl:strip-space elements="*"/> <my:halfhours> <t>00:00</t><t>00:30</t><t>01:00</t><t>01:30</t> <t>02:00</t><t>02:30</t><t>03:00</t><t>03:30</t> <t>04:00</t><t>04:30</t><t>05:00</t><t>05:30</t> <t>06:00</t><t>06:30</t><t>07:00</t><t>07:30</t> <t>08:00</t><t>08:30</t><t>09:00</t><t>09:30</t> <t>10:00</t><t>10:30</t><t>11:00</t><t>11:30</t> <t>12:00</t><t>12:30</t><t>13:00</t><t>13:30</t> <t>14:00</t><t>14:30</t><t>15:00</t><t>15:30</t> <t>16:00</t><t>16:30</t><t>17:00</t><t>17:30</t> <t>18:00</t><t>18:30</t><t>19:00</t><t>19:30</t> <t>20:00</t><t>20:30</t><t>21:00</t><t>21:30</t> <t>22:00</t><t>22:30</t><t>23:00</t><t>23:30</t> <t>24:00</t> </my:halfhours> <xsl:variable name="vhalfhrs" select= "document('')/*/my:halfhours/*"/> <xsl:template match="row"> <xsl:variable name="vstart" select= "$vhalfhrs[translate(.,':','') > translate(current()/time,':','') ][1] /preceding-sibling::*[1] "/> <xsl:variable name="vprecrow" select= "preceding-sibling::*[1]"/> <xsl:if test= "not(translate($vprecrow/time,':','') >= translate($vstart,':','') )"> <xsl:value-of select="concat('
',$vstart, ' $')"/> <xsl:value-of select= "sum(sales|following-sibling::* [not(translate(time,':','') >= translate($vstart/following-sibling::*,':','') ) ] /sales ) "/> </xsl:if> </xsl:template> </xsl:stylesheet> when transformation applied on same xml document, again wanted, correct result produced:
08:00 $1615 08:30 $1675 11:00 $1100 11:30 $1145 14:00 $1415 14:30 $1430 explanation:
in variable
$vhalfhrshave elements values starting time of every half-hour period during day.in template matches every
row,$vstartvariable set ti half-hour start-time, intimeof current node (row) falls into.the variable
$vprecrowset preceding sibling (row) of currentrow.if time of preceding
rownot later start-half-hour-time (in $vstart), currentrow` first 1 in half-hour period.we output starting half-hour period time.
we calculate , output sum of
rowelementstimein same half-hour time period. following siblings of currentrow,timenot greater or equal start of next half-hour period.
solution 3 (xslt 2.0):
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform" xmlns:xs="http://www.w3.org/2001/xmlschema"> <xsl:output method="text"/> <xsl:template match="/*"> <xsl:for-each-group select="row" group-adjacent= "(xs:integer(substring-before(time,':'))*60 + xs:integer(substring-after(time,':')) ) idiv 30 "> <xsl:variable name="vstartminutes" select="current-grouping-key()*30"/> <xsl:value-of separator="" select= "'
', format-number($vstartminutes idiv 60, '00'), ':', format-number($vstartminutes mod 60,'00'), ' $', sum(current-group()/sales/xs:integer(.)) "/> </xsl:for-each-group> </xsl:template> </xsl:stylesheet> when transformation applied on same xml document above, same wanted, correct result produced:
08:00 $1615 08:30 $1675 11:00 $1100 11:30 $1145 14:00 $1415 14:30 $1430 explanation:
we using
<xsl:for-each-group>group-adjacentattribute set expression calculating position of 1/2 hour period inrow/timeis.heavy use of standard functions
current-group(),current-grouping-key().
Comments
Post a Comment