Это преобразование (имеющее наименьшее количество шаблонов - всего 3, оно короче всех других текущих решений и устойчиво к порядку элементов или отсутствует col
элементов):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="col[not(position()=last())]">
<xsl:value-of select="concat(.,'|')"/>
</xsl:template>
<xsl:template match="row">
<xsl:text>
</xsl:text>
<xsl:apply-templates select="/*/col"
mode="buildCell">
<xsl:with-param name="pRow" select="."/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="col" mode="buildCell">
<xsl:param name="pRow"/>
<xsl:value-of select=
"concat($pRow/*[name()=current()],
substring('|', (position()=last())+1)
)
"/>
</xsl:template>
</xsl:stylesheet>
при применении к предоставленному документу XML:
<grid>
<col>Links</col>
<col>Rechts</col>
<row>
<Links>l1</Links>
<Rechts>r1</Rechts>
</row>
<row>
<Links>l2</Links>
<Rechts>r2</Rechts>
</row>
</grid>
дает требуемый, правильный результат:
Links|Rechts
l1|r1
l2|r2