I. Решение XSLT 1.0 :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kRecByGrId" match="DATA_RECORD"
use="GROUP_ID"/>
<xsl:variable name="vGrIds" select=
"/*/DATA_RECORD
[generate-id()
=
generate-id(key('kRecByGrId', GROUP_ID)[1])
]
/GROUP_ID
"/>
<xsl:template match="/">
<xsl:variable name="vResult">
<xsl:for-each select="$vGrIds">
<xsl:if test="not(position()=1)">|</xsl:if>
<xsl:apply-templates select=
"key('kRecByGrId', .)/COMPONENT_SID"/>
</xsl:for-each>
</xsl:variable>
<comp value="{$vResult}"/>
</xsl:template>
<xsl:template match="COMPONENT_SID">
<xsl:if test="not(position()=1)">,</xsl:if>
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
при применении к предоставленному документу XML :
<main>
<DATA_RECORD>
<COMPONENT_SID>100</COMPONENT_SID>
<GROUP_ID>1</GROUP_ID>
</DATA_RECORD>
<DATA_RECORD>
<COMPONENT_SID>200</COMPONENT_SID>
<GROUP_ID>1</GROUP_ID>
</DATA_RECORD>
<DATA_RECORD>
<COMPONENT_SID>400</COMPONENT_SID>
<GROUP_ID>1</GROUP_ID>
</DATA_RECORD>
<DATA_RECORD>
<COMPONENT_SID>10</COMPONENT_SID>
<GROUP_ID>2</GROUP_ID>
</DATA_RECORD>
<DATA_RECORD>
<COMPONENT_SID>20</COMPONENT_SID>
<GROUP_ID>2</GROUP_ID>
</DATA_RECORD>
<DATA_RECORD>
<COMPONENT_SID>2</COMPONENT_SID>
<GROUP_ID>3</GROUP_ID>
</DATA_RECORD>
<DATA_RECORD>
<COMPONENT_SID>4</COMPONENT_SID>
<GROUP_ID>3</GROUP_ID>
</DATA_RECORD>
<DATA_RECORD>
<COMPONENT_SID>8</COMPONENT_SID>
<GROUP_ID>3</GROUP_ID>
</DATA_RECORD>
<DATA_RECORD>
<COMPONENT_SID>16</COMPONENT_SID>
<GROUP_ID>3</GROUP_ID>
</DATA_RECORD>
</main>
дает желаемый, правильный результат :
<comp value="100,200,400|10,20|2,4,8,16"/>
Объяснение
мюнхенский метод группировки - найти все различные значения GROUP_ID
.
Простая логика для добавления элемента (или группы) к разделителю , если этот элемент (или группа) не первый.
II. Решение XSLT 2.0 :
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="vResult">
<xsl:for-each-group select="*/*" group-by="GROUP_ID">
<xsl:if test="not(position()=1)">|</xsl:if>
<xsl:for-each select="current-group()/COMPONENT_SID">
<xsl:if test="not(position()=1)">,</xsl:if>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:for-each-group>
</xsl:variable>
<comp value="{$vResult}"/>
</xsl:template>
</xsl:stylesheet>
при применении к тому же XML-документу (см. Выше), снова желаемый, правильный результат :
<comp value="100,200,400|10,20|2,4,8,16"/>
Объяснение
Использование <xsl:for-each-group>
Использование current-group()
Та же самая простая логика для предшествующего каждому элементу (или группе), который не является первым, с соответствующим разделителем.