Reputation: 309
I have a list of timecards to list as output in MS Word through WordML (using XSLT 2.0) and think I need to do some sort of grouping that I'm not certain how to complete (if at all possible).
What the higher ups are looking for is by each date (sorted by date), all the info rolled into one section for each timekeeper. (Date, Timekeeper Initials, Sum of Hours for that date, list of all Narrative data for that timekeeper for that date).
Here's what I currently have, which is just by each timekeeper / timecard per date, no grouping in place.
INPUT:
<xml-sample>
<timecard index="10">
<timekeeper>
<initials>NC1</initials>
</timekeeper>
<date type="timecard">2015-09-01</date>
<card-values>
<card-value type="billed">
<rate>325.00</rate>
<hours>0.20</hours>
<amount>65.0000</amount>
</card-value>
</card-values>
<narrative>
<line id="1">Narrative for 9/1/2015. With some more detail</line>
<line id="2">on the 2nd line ID.</line>
</narrative>
</timecard>
<timecard index="11">
<timekeeper>
<initials>NC1</initials>
</timekeeper>
<date type="timecard">2015-09-01</date>
<card-values>
<card-value type="billed">
<rate>325.00</rate>
<hours>0.40</hours>
<amount>130.0000</amount>
</card-value>
</card-values>
<narrative>
<line id="1">Another narrative for 9/1/2015. With some more</line>
<line id="2">detail on the 2nd line ID.</line>
</narrative>
</timecard>
<timecard index="12">
<timekeeper>
<initials>NC1</initials>
</timekeeper>
<date type="timecard">2015-09-12</date>
<card-values>
<card-value type="billed">
<rate>325.00</rate>
<hours>0.30</hours>
<amount>97.5000</amount>
</card-value>
</card-values>
<narrative>
<line id="1">Narrative for 9/12/2015. With some more detail</line>
<line id="2">detail on the 2nd line ID.</line>
</narrative>
</timecard>
CURRENT CODE:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:aml="http://schemas.microsoft.com/aml/2001/core"
xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:kmf="http://www.kleinmundo.com/functions"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:sl="http://schemas.microsoft.com/schemaLibrary/2003/core"
xmlns:tlr="http://www.elite.com/functions"
xmlns:st1="urn:schemas-microsoft-com:office:smarttags"
xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:w="http://schemas.microsoft.com/office/word/2003/wordml"
xmlns:w10="urn:schemas-microsoft-com:office:word"
xmlns:wsp="http://schemas.microsoft.com/office/word/2003/wordml/sp2"
xmlns:wx="http://schemas.microsoft.com/office/word/2003/auxHint"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template name="Time_Detail_Sample">
<xsl:for-each select="xsm-sample/timecard">
<w:p>
<w:r>
<w:t>Date: <xsl:value-of select="format-date(date, '[M01]/[D01]/[Y01]')" />
</w:t>
</w:r>
</w:p>
<w:p>
<w:r>
<w:t>Timekeeper: <xsl:value-of select="timekeeper/initials" />
</w:t>
</w:r>
</w:p>
<w:p>
<w:r>
<w:t>Hours: <xsl:value-of select="format-number(card-values/card-value[@type='billed']/hours, '###,##0.00')" />
</w:t>
</w:r>
</w:p>
<w:p>
<w:r>
<xsl:for-each select="narrative/line">
<w:t>
<xsl:value-of select="(.)" />
<xsl:value-of select="' '" />
</w:t>
</xsl:for-each>
</w:r>
</w:p>
<w:p />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
CURRENT OUTPUT:
DESIRED OUTPUT: (as you can see, the data for 9/1/2015 are rolled into a SUM of hours and all of the Narrative details listed out all together).
Upvotes: 1
Views: 161
Reputation: 52858
I'd definitely use xsl:for-each-group
...
<xsl:for-each-group select="timecard"
group-by="string-join((timekeeper/initials,date[@type='timecard']),'|')">
<xsl:sort select="date[@type='timecard']"/>
<w:p>
<w:r>
<w:t>
<xsl:text>Date: </xsl:text>
<xsl:value-of select="format-date(date, '[M01]/[D01]/[Y01]')"/>
</w:t>
</w:r>
</w:p>
<w:p>
<w:r>
<w:t>
<xsl:text>Timekeeper: </xsl:text>
<xsl:value-of select="timekeeper/initials"/>
</w:t>
</w:r>
</w:p>
<w:p>
<w:r>
<w:t>
<xsl:text>Hours: </xsl:text>
<xsl:value-of select="format-number(sum(current-group()/card-values/card-value[@type='billed']/hours), '###,##0.00')"/>
</w:t>
</w:r>
</w:p>
<w:p>
<w:r>
<w:t>
<xsl:value-of select="current-group()/narrative/line" separator=" "/>
</w:t>
</w:r>
</w:p>
<w:p/>
</xsl:for-each-group>
Upvotes: 1
Reputation: 1377
I'd suggest to first get all distinct values of the date
, then put all timecard
elements with the current date into a variable and and then extracting whatever you want out of this variable.
So, something like:
<xsl:variable name="root" select="/"/>
<xsl:for-each select="distinct-values(//date[@type='timecard'])">
<xsl:variable name="current_value" select="."/>
<xsl:variable name="all_timecards_with_current_date" select="$root//timecard[descendant::date=$current_value]"/>
<w:p>
<w:r>
<w:t>Date: <xsl:value-of select="format-date($current_value, '[M01]/[D01]/[Y01]')" />
</w:t>
</w:r>
</w:p>
<w:p>
<w:r>
<w:t>Hours: <xsl:value-of select="sum($all_timecards_with_current_date//card-values/card-value[@type='billed']/hours)" />
</w:t>
</w:r>
</w:p>
<w:p>
<w:r>
<xsl:for-each select="$all_timecards_with_current_date//narrative/line">
<w:t>
<xsl:value-of select="." />
</w:t>
</xsl:for-each>
</w:r>
</w:p>
</xsl:for-each>
Not really pretty and surely not the fastest way. However, in my opinion it's easier to handle than grouping.
Upvotes: 0