Использование XSLT 1.0, следующее решение исправна - тестирование с помощью примера XML с 6 элементами:
<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>
Результат:
<?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>
Как краткое объяснение - в "баре" соответствия шаблона все Элемент-узлы обрабатываются в
<xsl:for-each select="*/node()">
Использование <xsl:if test="(position()-1) mod(3) = 0">
(w hich равно 0 для 1-го узла и для каждого третьего узла), шаблон, называемый «группировка», вызывается для обеспечения групп генерации из 3 узлов. Этот шаблон вызывается с положением параметров - положением текущего узла - и количеством - количеством узлов, которые должны быть скопированы в каждой группе.
Шаблон группировки копирует текущий узел - <xsl:copy-of select="//bar/*[$position]"/>
- проверяет, были ли уже созданы 3 узла - <xsl:if test="$amount > $position or ($position mod(3) > 0)">
- и снова вызывает себя, увеличивая счетчик в позиции, поэтому следующий узел будет скопирован.
На всякий случай это не очевидно - шаблон группировки будет вызван для $amount > $position
, поэтому будут скопированы первые 3 узла и для $position mod(3) > 0
для всех следующих узлов, если он не кратен 3. В случае, если будет, например, 7-й элемент в вашем xml, это будет скопировано как один элемент в группе data
.
Это проблема * группировки * (выполнить поиск). Решения очень разные, если вы используете XSLT 1.0 или 2.0 - пожалуйста, выберите один (теги должны быть взаимоисключающими). –