Следующее решение работает для любого имени поля и любого количества полей. Формат ваших данных предполагает, что имена полей могут быть динамическими. Также не предполагается, что поле children всегда будет называться «string». (Название «строка» вызвало у меня подозрение, что могут появиться другие типы данных. Независимо от того, делают они это или нет, это решение все равно будет работать.)
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="/">
<records>
<!-- Just process the first field's children,
to get the list of line items -->
<xsl:apply-templates select="/recordset/field[1]/*"/>
</records>
</xsl:template>
<!-- Convert each field child to a line item -->
<xsl:template match="field/*">
<item_line>
<!-- Then query all the fields for the value at this position -->
<xsl:apply-templates select="/recordset/field">
<xsl:with-param name="pos" select="position()"/>
</xsl:apply-templates>
</item_line>
</xsl:template>
<xsl:template match="field">
<xsl:param name="pos"/>
<!-- Convert the field name to lower case -->
<xsl:element name="{translate(
@name,
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'abcdefghijklmnopqrstuvwxyz'
)}">
<xsl:value-of select="*[$pos]"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Дайте мне знать, если у вас есть какие-либо вопросы.
РЕДАКТИРОВАТЬ: упрощенная версия выше:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="/">
<records>
<xsl:for-each select="/recordset/field[1]/*">
<xsl:variable name="pos" select="position()" />
<item_line>
<xsl:apply-templates select="/recordset/field/*[$pos]" />
</item_line>
</xsl:for-each>
</records>
</xsl:template>
<xsl:template match="field/*">
<xsl:element name="{translate(
../@name,
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'abcdefghijklmnopqrstuvwxyz'
)}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>