I would like to convert the following XML to a text file, so that the type and date of the cars appear only once in the header, but the times are listed below. And the header is created with a daily breakdown. I tried grouping first and without grouping, but so far I can't find the solution. Please advise how I can do this. Thanks.
input XML:
<?xml version="1.0" encoding="UTF-8"?>
<data>
<item>
<Date>2023-02-19</Date>
<Cars>Ford</Cars>
<SellTarget>A4+</SellTarget>
<Time>10:40:09</Time>
<avg>19.3464027998</avg>
</item>
<item>
<Date>2023-02-19</Date>
<Cars>Ford</Cars>
<SellTarget>A4+</SellTarget>
<Time>11:21:56</Time>
<avg>32.7150023474</avg>
</item>
<item>
<Date>2023-02-19</Date>
<Cars>Ford</Cars>
<SellTarget>A4+</SellTarget>
<Time>19:01:27</Time>
<avg>554.0289810087</avg>
</item>
<item>
<Date>2023-02-19</Date>
<Cars>Ford</Cars>
<SellTarget>A4+</SellTarget>
<Time>23:15:26</Time>
<avg>46.1398232343</avg>
</item>
<item>
<Date>2023-02-19</Date>
<Cars>Opel</Cars>
<SellTarget>A4+</SellTarget>
<Time>14:05:51</Time>
<avg>41.7428144493</avg>
</item>
<item>
<Date>2023-02-19</Date>
<Cars>Opel</Cars>
<SellTarget>A4+</SellTarget>
<Time>15:01:02</Time>
<avg>65.6303001034</avg>
</item>
<item>
<Date>2023-02-19</Date>
<Cars>Opel</Cars>
<SellTarget>A4+</SellTarget>
<Time>02:00:00</Time>
<avg>1.2954721559</avg>
</item>
</data>
XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:key name="carsgroup" match="/data/item" use="concat(Cars, '|', Date)" />
<xsl:variable name="tab" select="'	'"/>
<xsl:variable name="newLine" select="' '"/>
<xsl:variable name="csvSeparator" select="$tab"/>
<xsl:template match="/">
<xsl:call-template name="headerlines"/>
<xsl:apply-templates select="data/item[generate-id() = generate-id(key('carsgroup',
concat(Cars, '|', Date)))]" mode="dataRows">
</xsl:apply-templates>
</xsl:template>
<xsl:template name="headerlines">
<!-- 1. line is Skipped -->
<xsl:call-template name="csv">
<xsl:with-param name="val" select="''"/>
</xsl:call-template>
<!-- 2. line is Skipped-->
<xsl:call-template name="csv">
<xsl:with-param name="val" select="''"/>
</xsl:call-template>
<!-- 3. line is Skipped -->
<xsl:call-template name="csv">
<xsl:with-param name="val" select="''"/>
</xsl:call-template>
<!-- 4. line is Skipped -->
<xsl:call-template name="csv">
<xsl:with-param name="val" select="''"/>
<xsl:with-param name="isLastCol" select="true()"/>
</xsl:call-template>
</xsl:template>
<xsl:template match="item" mode="dataRows">
<!-- at 5. line the first 5 char is skipped -->
<xsl:call-template name="csv">
<xsl:with-param name="val" select="concat(' ', Cars, ' / ', Date, ' [ 50 Entrants ]')"/>
</xsl:call-template>
<!-- sequence number -->
<xsl:call-template name="csv">
<xsl:with-param name="val" select="position()"/>
</xsl:call-template>
<!-- Time HH:MM:SS -->
<xsl:call-template name="csv">
<xsl:with-param name="val" select="Time"/>
</xsl:call-template>
<!-- avg -->
<xsl:call-template name="csv">
<xsl:with-param name="val" select="avg"/>
<xsl:with-param name="isLastCol" select="true()"/>
<xsl:with-param name="isEOF" select="position()=last()"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="csv">
<xsl:param name="val"/>
<xsl:param name="isLastCol" select="false()"/>
<xsl:param name="isEOF" select="false()"/>
<xsl:value-of select="$val"/>
<xsl:choose>
<xsl:when test="$isLastCol and not($isEOF)">
<xsl:value-of select="$newLine"/>
</xsl:when>
<xsl:when test="not($isEOF)">
<xsl:value-of select="$csvSeparator"/>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
output text file atm:
Ford / 2023-02-19 [ 50 Entrants ] 1 10:40:09 19.3464027998
Opel / 2023-02-19 [ 50 Entrants ] 2 14:05:51 41.7428144493
What i want:
Ford / 2023-02-19 [ 50 Entrants ]
1 10:40:09 19.3464027998
2 11:21:56 32.7150023474
3 19:01:27 554.0289810087
4 23:15:26 46.1398232343
Opel / 2023-02-19 [ 50 Entrants ]
1 02:00:00 1.2954721559
2 14:05:51 41.7428144493
3 15:01:02 65.6303001034
Muenchian grouping usually works in two stages: first you identify the first item in each group and create a group; then you process the items in this group. The problem with your attempt is that it lacks the second part.
Try adapting this simplified stylesheet:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:key name="carsgroup" match="item" use="concat(Cars, '|', Date)" />
<xsl:template match="/data">
<xsl:for-each select="item[generate-id() = generate-id(key('carsgroup', concat(Cars, '|', Date))[1])]">
<!-- group header -->
<xsl:value-of select="Cars"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="Date"/>
<xsl:text> </xsl:text>
<!-- group items -->
<xsl:for-each select="key('carsgroup', concat(Cars, '|', Date))">
<xsl:value-of select="position()"/>
<xsl:text>	</xsl:text>
<xsl:value-of select="Time"/>
<xsl:text>	</xsl:text>
<xsl:value-of select="avg"/>
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>