Re: [xsl] different evaluations on sibling elements ...

Subject: Re: [xsl] different evaluations on sibling elements ...
From: Michael Kay <mike@xxxxxxxxxxxx>
Date: Tue, 27 Aug 2013 00:08:36 +0100
Your existing code seems to be pure XSLT 1.0. If that's a constraint, you
should say so, since it will make the solution a lot more difficult.

Michael Kay
Saxonica

On 26 Aug 2013, at 17:33, Raimund Kammering wrote:

> Hi,
>
> i need to build up two tables listing periods between timestamps plus some
categories. I got the math with evaluating the time periods running but am
stuck on building additionally a summary table for the appearances of the
categories. Here is what I have:
>
> XML:
> -------
> <list>
>  <url_base>/2013/06/09.02_n</url_base>
>  <entry>
>    <severity>STATISTICS</severity>
>    <isodate>2013-02-09</isodate>
>    <time>23:00:00</time>
>    <statistics_category>Delivery</statistics_category>
>  </entry>
>  <entry>
>    <severity>STATISTICS</severity>
>    <isodate>2013-02-10</isodate>
>    <time>00:37:33</time>
>    <statistics_category>Tuning</statistics_category>
>    <tuning>Problems</tuning>
>  </entry>
>  <entry>
>    <severity>STATISTICS</severity>
>    <isodate>2013-02-10</isodate>
>    <time>02:59:03</time>
>    <statistics_category>Delivery</statistics_category>
>  </entry>
>  <entry>
>    <severity>STATISTICS</severity>
>    <isodate>2013-02-10</isodate>
>    <time>03:27:39</time>
>    <statistics_category>Tuning</statistics_category>
>    <tuning>Quality</tuning>
>  </entry>
>  <entry>
>    <severity>STATISTICS</severity>
>    <isodate>2013-02-10</isodate>
>    <time>03:42:09</time>
>    <statistics_category>Delivery</statistics_category>
>  </entry>
>  <entry>
>    <severity>STATISTICS</severity>
>    <isodate>2013-02-10</isodate>
>    <time>04:18:11</time>
>    <statistics_category>Down</statistics_category>
>    <down>RF</down>
>  </entry>
> </list>
>
> XSL:
> -------
>  <xsl:param name="url_base">
>    <xsl:value-of select="/list/url_base"/>
>  </xsl:param>
>
>  <xsl:template name="statistics_details">
>
>      <table>
>      <tr><td colspan="3">Detailed statistics</td></tr>
>      <tr><td></td><td></td><td>Start</td><td>End</td><td>duration
[hours]</td><td>Category</td><td>Reason</td></tr>
>
>    <xsl:for-each select="entry[severity!='DELETE']/statistics_category">
>      <xsl:sort order="descending" select="../isodate"/>
>      <xsl:sort order="descending" select="../time"/>
>
>      <xsl:variable name="end_time">
>        <xsl:choose>
>          <xsl:when
test="ancestor::entry/following-sibling::entry[severity!='DELETE']/statistics
_category">
>            <!-- FIXME - will fail if two or more consecutive deletes follow!
-->
>              <xsl:value-of
select="ancestor::entry/following-sibling::entry[severity!='DELETE']/statisti
cs_category/../time"/>
>          </xsl:when>
>          <!-- last log -->
>          <xsl:otherwise>
>            <xsl:choose>
>              <xsl:when test="substring($url_base, string-length($url_base)
)='M'">
>                <xsl:value-of select="'15:00:00'"/>
>              </xsl:when>
>              <xsl:when test="substring($url_base, string-length($url_base)
)='a'">
>                <xsl:value-of select="'23:00:00'"/>
>              </xsl:when>
>              <xsl:when test="substring($url_base, string-length($url_base)
)='n'">
>                <xsl:value-of select="'07:00:00'"/>
>              </xsl:when>
>              <xsl:otherwise>
>                <xsl:text>ERROR: Could not determine shift end</xsl:text>
>              </xsl:otherwise>
>            </xsl:choose>
>          </xsl:otherwise>
>        </xsl:choose>
>      </xsl:variable>
>
>      <xsl:variable name="end_date">
>        <xsl:choose>
>          <xsl:when
test="ancestor::entry/following-sibling::entry[severity!='DELETE']/statistics
_category">
>            <!-- FIXME - will fail if two or more consecutive deletes follow!
-->
>              <xsl:value-of
select="ancestor::entry/following-sibling::entry[severity!='DELETE']/statisti
cs_category/../isodate"/>
>          </xsl:when>
>          <xsl:otherwise>
>            <xsl:choose>
>              <xsl:when test="substring($url_base, string-length($url_base)
)='M'">
>                <xsl:value-of select="substring-before(date:date(),'+')"/>
>              </xsl:when>
>              <xsl:when test="substring($url_base, string-length($url_base)
)='a'">
>                <xsl:value-of select="substring-before(date:date(),'+')"/>
>              </xsl:when>
>              <xsl:when test="substring($url_base, string-length($url_base)
)='n'">
>                <xsl:choose>
>                  <xsl:when test="substring(../time, 1, 1)!='0'">
>                    <xsl:call-template name="date:add">
>                      <xsl:with-param name="date-time" select="../isodate"
/>
>                      <xsl:with-param name="duration" select="'P1D'" />
>                    </xsl:call-template>
>                  </xsl:when>
>                  <xsl:otherwise>
>                    <xsl:value-of select="../isodate"/>
>                  </xsl:otherwise>
>                </xsl:choose>
>              </xsl:when>
>              <xsl:otherwise>
>                <xsl:value-of select="substring-before(date:date(),'+')"/>
>              </xsl:otherwise>
>            </xsl:choose>
>          </xsl:otherwise>
>        </xsl:choose>
>      </xsl:variable>
>
>      <xsl:variable name="start_time" select="../time"/>
>
>      <xsl:variable name="end" select="concat($end_date, 'T', $end_time)"/>
>      <xsl:variable name="start" select="concat(../isodate, 'T',
$start_time)"/>
>
>      <xsl:variable name="time-diff-dur">
>        <xsl:call-template name="date:difference">
>          <xsl:with-param name="start" select="$start" />
>          <xsl:with-param name="end" select="$end" />
>        </xsl:call-template>
>      </xsl:variable>
>
>      <!-- The above returns a duration formatted string, so convert that to
seconds: -->
>      <xsl:variable name="time-diff-sec">
>        <xsl:call-template name="duration2seconds">
>          <xsl:with-param name="duration" select="$time-diff-dur" />
>        </xsl:call-template>
>      </xsl:variable>
>
>      <tr>
>        <td></td><td></td>
>        <td><xsl:value-of select="$start_time"/></a></td>
>        <td><xsl:value-of select="$end_time"/></td>
>        <td><xsl:value-of select="format-number($time-diff-sec div 3600,
'0.00')"/></td>
>        <td><xsl:value-of select="."/></td>
>        <xsl:choose>
>            <xsl:when test=".='Tuning'">
>                <td><xsl:value-of select="../Tuning"/></td>
>            </xsl:when>
>            <xsl:when test=".='Down'">
>                <td><xsl:value-of select="../Down"/></td>
>            </xsl:when>
>            <xsl:otherwise>
>                <td></td></xsl:otherwise>
>        </xsl:choose>
>      </tr>
>
>    </xsl:for-each>
>
>  </table>
>  </xsl:template>
>
> HTML Output:
> -------------------
> Detailed statistics
> Start	End	duration [hours]	Category
> 04:18:11	07:00:00	2.70	Down	RF
> 03:42:09	04:18:11	0.60	Delivery
> 03:27:39	03:42:09	0.24	Tuning	Quality
> 02:59:03	03:27:39	0.48	Delivery
> 00:37:33	02:59:03	2.36	Tuning	Problems
> 23:00:00	00:37:33	1.63	Delivery
>
> I completely omit here the stuff needed for the time difference calculation
etc., since this all  works just fine and is quite impressive - thanks to the
xsl-list's previous help!! But now I would like to have above the 'Detailed
statistics' section a 'Statistics Summary' showing the sums for the statistics
categories. So that the final html would look like this:
>
> Desired HTML Output:
> ------------------------------
> Statistics Summary
> Delivery: 2.71	Tuning: 2.60		Down: 2.70
>
> Detailed statistics
> Start	End	duration [hours]	Category
> 04:18:11	07:00:00	2.70	Down	RF
> 03:42:09	04:18:11	0.60	Delivery
> 03:27:39	03:42:09	0.24	Tuning	Quality
> 02:59:03	03:27:39	0.48	Delivery
> 00:37:33	02:59:03	2.36	Tuning	Problems
> 23:00:00	00:37:33	1.63	Delivery
>
> I thought of several of the 'standard trick' like recursion and/or calling
template with modes, but never got a clear picture how to manage it (this
nasty thing with the needed relation between the two consecutive 'entry'
elements ). Any idea on how to approach this would be greatly welcome!!
>
> And yes some of the calling logic I left out, since this is not the tricky
part and the above should hopefully sketch the problem sufficiently (and for
simplicity I left out the case of an entry having severity='DELETE' ;-)!?
>
> Cheers,
> Raimund

Current Thread