XSLT 1.0 - Concatenating each Nth subelement of a recurring element

44 views Asked by At

I have an XML with the following structure:

<Root>
<Record>
    <Field1>ABC</Field1>
    <Field2>DEF</Field2>
    <MatchingSubRecords>
        <SubField1>SUB01</SubField1>
        <SubField2>SUB02</SubField2>
    </MatchingSubRecords>  
    <MatchingSubRecords>
        <SubField1>SUB11</SubField1>
        <SubField2>SUB11</SubField2>
    </MatchingSubRecords>  
    <MatchingSubRecords>
        <SubField1>SUB21</SubField1>
        <SubField2>SUB22</SubField2>
    </MatchingSubRecords>  
</Record>
</Root>

Whilst I have a simple XSLT to transform every record into a text output of

Field1, Field2
ABC,DEF

I would like to either have every matching sub records in a similar CSV output either as a separate file or with a separate delimitting character as part of the main CSV output itself, something like

ABC, DEF, "SUB01,SUB11,SUB21|SUB02,SUB12,SUB22"

If there is a possibility in using XslCompiledTransform to stream write it as two files, that would be perfect. If not, I would have to parse it later, which is fine as well.

2

There are 2 answers

1
Amrendra Kumar On

By simple transformation you can achive the desire output:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="1.0">

    <xsl:output method="text"/>

    <xsl:template match="/Root/Record">
        <xsl:value-of select="concat(Field1, ',', Field2, '&#x000a;')"/>
        <xsl:for-each select="MatchingSubRecords">
            <xsl:value-of select="concat(SubField1, ',', SubField2)"/>
            <xsl:text>&#x000a;</xsl:text>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

If you have multiple n number of occurances then you can use like below without specifying element name:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="1.0">

    <xsl:output method="text"/>

    <xsl:template match="/Root/Record">
        <xsl:for-each select="*[not(self::MatchingSubRecords)]">
            <xsl:value-of select="."/>
            <xsl:if test="position()!=last()">
                <xsl:text>,</xsl:text>
            </xsl:if>
        </xsl:for-each>
        <xsl:for-each select="MatchingSubRecords">
            <xsl:text>&#x000a;</xsl:text>
            <xsl:for-each select="*">
                <xsl:value-of select="."/>
                    <xsl:if test="position()!=last()">
                        <xsl:text>,</xsl:text>
                    </xsl:if>
            </xsl:for-each>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

See this link for your reference: https://xsltfiddle.liberty-development.net/ejivdHr

1
Ansari On

You can try this one:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="1.0">

    <xsl:output method="text"/>

    <xsl:template match="/Root/Record">
        <xsl:value-of select="concat(Field1, ', ', Field2, ', ')"/>
        <xsl:text>"</xsl:text>
        <xsl:for-each select="MatchingSubRecords/SubField1">
            <xsl:value-of select="."/>
            <xsl:if test="position() != last()">
                <xsl:text>,</xsl:text>
            </xsl:if>
        </xsl:for-each>
        <xsl:text>|</xsl:text>
        <xsl:for-each select="MatchingSubRecords/SubField2">
            <xsl:value-of select="."/>
            <xsl:if test="position() != last()">
                <xsl:text>,</xsl:text>
            </xsl:if>
        </xsl:for-each>
        <xsl:text>"</xsl:text>
    </xsl:template>
</xsl:stylesheet>