Reputation: 2317
Two issues here. I have XML structured like the following:
<root>
<Detection>
<Time>2000-01-01T00:12:00Z</Time>
</Detection>
<Detection>
<Time>2000-01-01T00:34:00Z</Time>
</Detection>
<Detection>
<Time>2000-01-01T02:33:00Z</Time>
</Detection>
</root>
I would like to transform this xml by matching elements based on a date range. Specifically,<Detection>s
that occur in the same hour should be grouped together, and replaced with a single <Detection>
specifying that hour, including a <Count>
element which tells us how many original <Detection>s
are in this new <Detection>
. Confusing?
Example output based on above input:
<root>
<Detection>
<!-- there were two detections occuring during the midnight hour -->
<Time>2000-01-01T00:00:00Z</Time>
<Count>2</Count>
</Detection>
<Detection>
<!-- there was one detection during the 2 oclock hour -->
<Time>2000-01-01T02:00:00Z</Time>
<Count>1</Count>
</Detection>
</root>
I am just beginning with XSLT. xsl:for-each-group
seems to be the function of interest. The difficulty appears to be deriving an hourly DateTime (eg 00:00:00) from a DateTime element's value (eg 00:12:00). The second difficulty is keeping track of how many elements have been binned. So as to not have this simply solved for me, my question is simply:
is this possible(not extremely difficult) to do with XSLT?
any further input or examples are very much appreciated!
Upvotes: 0
Views: 1082
Reputation: 70638
If you are only interested in the hourly portion, and are not rounding up/down to the nearest hour, just 'group by' the part of Time that occurs before the first :
<xsl:for-each-group select="Detection" group-by="substring-before(Time, ':')">
Then, it is not a case of 'binning' elements. The current-group()
function can be used to get all the Detection that are in your group. For example
<Count><xsl:value-of select="count(current-group())" /></Count>
Try this XSLT
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="root">
<xsl:copy>
<xsl:for-each-group select="Detection" group-by="substring-before(Time, ':')">
<xsl:copy>
<Time><xsl:value-of select="substring-before(Time, ':')" />:00:00Z</Time>
<Count><xsl:value-of select="count(current-group())" /></Count>
</xsl:copy>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:transform>
Upvotes: 2