Using XSLT 1.0, following solution is working - tested with your example XML with 6 elements:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/*">
<xsl:apply-templates select="/foo/bar"/>
</xsl:template>
<xsl:template match="bar">
<xsl:for-each select="*/node()">
<xsl:if test="(position()-1) mod(3) = 0">
<data>
<xsl:call-template name="grouping">
<xsl:with-param name="position" select="position()"/>
<xsl:with-param name="amount" select="3"/>
</xsl:call-template>
</data>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template name="grouping">
<xsl:param name="position" select="0"/>
<xsl:param name="amount" select="0"/>
<xsl:copy-of select="//bar/*[$position]"/>
<xsl:if test="$amount > $position or ($position mod(3) > 0)">
<xsl:call-template name="grouping">
<xsl:with-param name="position" select="$position + 1"/>
<xsl:with-param name="amount" select="$amount"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Result:
<?xml version="1.0" encoding="UTF-8"?>
<data>
<A>xxx</A>
<B>yyy</B>
<C>zzz</C>
</data>
<data>
<A>aaa</A>
<B>bbb</B>
<C>ccc</C>
</data>
As short explanation - in the template matching "bar" all element-nodes are processed in
<xsl:for-each select="*/node()">
By using <xsl:if test="(position()-1) mod(3) = 0">
(which is 0 for the 1st node and for every 3rd node) the template named "grouping" is called to provide generating groups of 3 nodes. This template is called with the parameters position - the position of the current node - and amount - the amount of nodes to be copied in each group.
The grouping-template copies the current node - <xsl:copy-of select="//bar/*[$position]"/>
- checks if already 3 nodes have been generated - <xsl:if test="$amount > $position or ($position mod(3) > 0)">
- and calls itself again, incrementing as counter the position, so the next node will be copied.
Just in case it's not obvious - the grouping-template will be called for $amount > $position
so the first 3 nodes will be copied, and for $position mod(3) > 0
for all following nodes as long as it's not a multiple of 3. In case there would be e.g. a 7th element in your xml, this would be copied as single element in a data
-group.