So I\'ve got an XML file I\'ve generated from a php curl response that is then transformed to CSV such that each mods element below is one line. I\'ve got some CSV using the sty
One way to do this is firstly change your XSLT to only select the elements which do not have a preceding-sibling with the same child name (i.e select elements that are the 'first' in each group)
<xsl:for-each select="*[name(*) != name(preceding-sibling::*[1]/*)]">
Then, you can define a variable to get the following sibling if (and only if) it has the same name, so you can then check if the current element is indeed in a group of more than 1.
<xsl:variable name="nextWithSameName"
select="following-sibling::*[1][name(*)=name(current()/*)]"/>
<xsl:if test="$nextWithSameName">**</xsl:if>
(I am not sure if you actually wanted the ** in the final results, or whether they are just there to highlight the group! I am keeping them in my example, but obviously it will be easy enough to remove the relevant lines of code).
To group together the following-siblings with the same name, you could call a recursive template for the first following-sibling
<xsl:apply-templates select="$nextWithSameName" mode="group"/>
Then, within this template you would recursively call it where the immediate following sibling has the same name
<xsl:template match="*" mode="group">
<xsl:text>;</xsl:text>
<xsl:value-of select="normalize-space(.)"/>
<xsl:apply-templates select="following-sibling::*[1][name(*)=name(current()/*)]" />
</xsl:template>
Try the following XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="iso-8859-1"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*/*">
<xsl:for-each select="*[name(*) != name(preceding-sibling::*[1]/*)]">
<xsl:variable name="nextWithSameName" select="following-sibling::*[1][name(*)=name(current()/*)]"/>
<xsl:if test="position() > 1">, </xsl:if>
<xsl:if test="$nextWithSameName">**</xsl:if>
<xsl:value-of select="normalize-space(.)"/>
<xsl:apply-templates select="$nextWithSameName" mode="group"/>
<xsl:if test="$nextWithSameName">**</xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="*" mode="group">
<xsl:text>;</xsl:text>
<xsl:value-of select="normalize-space(.)"/>
<xsl:apply-templates select="following-sibling::*[1][name(*)=name(current()/*)]" />
</xsl:template>
</xsl:stylesheet>
Now, if you could use XSLT 2.0, things become much, much easier, as you could use the xsl:for-each-group construct which, among other things, comes with an operation to 'group-adjacent'. And you could also do away with the recursive template by using the improved xsl:value-of which would have a 'separator' property to use when multiple elements are select.
For XSLT 2.0, the following should also work
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="iso-8859-1"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*/*">
<xsl:for-each-group select="*" group-adjacent="name(*)">
<xsl:if test="position() > 1">, </xsl:if>
<xsl:if test="current-group()[2]">**</xsl:if>
<xsl:value-of select="current-group()" separator=";" />
<xsl:if test="current-group()[2]">**</xsl:if>
</xsl:for-each-group >
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>