If I understand you correctly, the structure of the input is
<diffs>
<a/>
<b/>
<c/>
<d/>
<a/>
<b/>
<c/>
<d/>
</diffs>
where the element names of a,b,c,d can be anything, and we somehow need to arrange them in groups. Why the person generating this XML couldn't be troubled to insert begin/end tags around each group defeats me, but I guess its the usual story that they were prepared to "leave this as an exercise for the reader", i.e. you.
if you're absolutely confident that the pattern is regular and there is more than one row, then you can calculate the size of the group as being the position of the first element whose name matches the name of the first element, if you get my meaning: in XSLT 2.0 that's
Code:
<xsl:variable name="group-size" select="index-of(*/node-name(.), *[1]/node-name(.))[2]"/>
Having computed the group-size, you then have the standard task of arranging the data in fixed-size groups:
Code:
<xsl:for-each select="*[position() mod $group-size] = 1">
<tr>
<xsl:for-each select="(.|following-sibling)[position() <= $group-size()]">
<td><xsl:value-of select="."/></td>
</
</
</
and then all that's left is adding the table headings:
Code:
<xsl:for-each select="*[position() <= $group-size]">
<th><xsl:value-of select="local-name()"/></th>
</xsl:for-each>
If you want to output CSV rather than an HTML table the principles are the same but you need to do some mucking about to escape special characters in the text (commas and quotes).