user6742120
user6742120

Reputation: 175

How to transform Nested XML elements to flat XML

Hi I want to transform my XML with nested elements into flat XML where all nested elements comes in parallel

Input XML :

    <?xml version='1.0' encoding='UTF-8'?>
<Report_Data>
    <Report_Entry>
        <Employee_ID>02159</Employee_ID>
        <Name>ABC, DEF</Name>
        <Citizenship_Countries>United States of America</Citizenship_Countries>
    <National_Identifiers>
        <National_ID_Country>United States of America</National_ID_Country>
        <National_ID_Type_Name>Social Security Number (SSN)</National_ID_Type_Name>
        <National_ID_Unformatted>111111111</National_ID_Unformatted>
    </National_Identifiers>
    <Marital_Status>Married (United States of America)</Marital_Status>
    <Dependents>
        <Relationship>Child</Relationship>
        <Name>Ethan ABC</Name>
        <Age>12</Age>
    </Dependents>
    <Dependents>
        <Relationship>Child</Relationship>
        <Name>Holly ABC</Name>
        <Age>7</Age>
    </Dependents>
</Report_Entry>
<Report_Entry>
    <Employee_ID>04805</Employee_ID>
    <Name>dUMMY, ABC</Name>
    <Citizenship_Countries>United States of America</Citizenship_Countries>
    <National_Identifiers>
        <National_ID_Country>United States of America</National_ID_Country>
        <National_ID_Type_Name>Social Security Number (SSN)</National_ID_Type_Name>
        <National_ID_Unformatted>111111111</National_ID_Unformatted>
    </National_Identifiers>
    <Marital_Status>Married (United States of America)</Marital_Status>
    <Dependents>
        <Relationship>Child</Relationship>
        <Name>QWER dUMMY</Name>
        <Age>6</Age>
    </Dependents>
    <Dependents>
            <Relationship>Child</Relationship>
            <Name>ASDF dUMMY</Name>
            <Age>4</Age>
        </Dependents>
    </Report_Entry>
</Report_Data>

output XML :

<?xml version='1.0' encoding='UTF-8'?>
<Report_Data>
<Report_Entry>
    <Employee_ID>02159</Employee_ID>
    <Name>ABC, DEF</Name>
    <Citizenship_Countries>United States of America</Citizenship_Countries>
    <National_Identifiers_National_ID_Country>United States of America</National_Identifiers_National_ID_Country>
    <National_Identifiers_National_ID_Type_Name>Social Security Number (SSN)</National_Identifiers_National_ID_Type_Name>
    <National_Identifiers_National_ID_Unformatted>111111111</National_Identifiers_National_ID_Unformatted>
    <Marital_Status>Married (United States of America)</Marital_Status>
    <Dependent_Relationship>Child</Dependent_Relationship>
    <Dependent_Name>Ethan ABC</Dependent_Name>
    <Dependent_Age>12</Dependent_Age>
</Report_Entry>
<Report_Entry>
    <Employee_ID>02159</Employee_ID>
    <Name>ABC, DEF</Name>
    <Citizenship_Countries>United States of America</Citizenship_Countries>
    <National_Identifiers_National_ID_Country>United States of America</National_Identifiers_National_ID_Country>
    <National_Identifiers_National_ID_Type_Name>Social Security Number (SSN)</National_Identifiers_National_ID_Type_Name>
    <National_Identifiers_National_ID_Unformatted>111111111</National_Identifiers_National_ID_Unformatted>
    <Marital_Status>Married (United States of America)</Marital_Status>
    <Dependent_Relationship>Child</Dependent_Relationship>
    <Dependent_Name>Holly ABC</Dependent_Name>
    <Dependent_Age>7</Dependent_Age>
</Report_Entry>
<Report_Entry>
    <Employee_ID>04805</Employee_ID>
    <Name>dUMMY, ABC</Name>
    <Citizenship_Countries>United States of America</Citizenship_Countries>
    <National_Identifiers_National_ID_Country>United States of America</National_Identifiers_National_ID_Country>
    <National_Identifiers_National_ID_Type_Name>Social Security Number (SSN)</National_Identifiers_National_ID_Type_Name>
    <National_Identifiers_National_ID_Unformatted>111111111</National_Identifiers_National_ID_Unformatted>
    <Marital_Status>Married (United States of America)</Marital_Status>
    <Dependent_Relationship>Child</Dependent_Relationship>
    <Dependent_Name>QWER dUMMY</Dependent_Name>
    <Dependent_Age>6</Dependent_Age>
</Report_Entry>
<Report_Entry>
    <Employee_ID>04805</Employee_ID>
    <Name>dUMMY, ABC</Name>
    <Citizenship_Countries>United States of America</Citizenship_Countries>
    <National_Identifiers_National_ID_Country>United States of America</National_Identifiers_National_ID_Country>
    <National_Identifiers_National_ID_Type_Name>Social Security Number (SSN)</National_Identifiers_National_ID_Type_Name>
    <National_Identifiers_National_ID_Unformatted>111111111</National_Identifiers_National_ID_Unformatted>
    <Marital_Status>Married (United States of America)</Marital_Status>
    <Dependent_Relationship>Child</Dependent_Relationship>
    <Dependent_Name>ASDF dUMMY</Dependent_Name>
    <Dependent_Age>4</Dependent_Age>
</Report_Entry>
</Report_Data>

Note: My child element is same element with name "Name" under dependent element. So what I want in my output XML is name of dependent Name is to be with different element name like Dependent_Name

Upvotes: 0

Views: 1063

Answers (2)

uL1
uL1

Reputation: 2167

Besides your question-title differs from the real thread, i show you one way to solve it. It does use less hardcoded pathes so it is a more generic way.

Whenever a childnode of a child of Report_Entry exists, it will get flatten with the name of parent. I hope you don't need any further deeper levels. [not included in question and solution]

I. XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
    <xsl:output method="xml" indent="yes"/>
    <xsl:strip-space elements="Report_Entry National_Identifiers Dependents"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Report_Data">
        <xsl:copy>
            <xsl:for-each select="Report_Entry/Dependents">
                <xsl:element name="Report_Entry">
                    <xsl:apply-templates select="../*[not(self::Dependents)] | ."/>
                </xsl:element>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Report_Entry/*[*]">
        <xsl:apply-templates />
    </xsl:template>

    <xsl:template match="Report_Entry/*/*">
        <xsl:element name="{concat(name(parent::*), '_', name())}">
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

Upvotes: 1

michael.hor257k
michael.hor257k

Reputation: 117165

Your question is somewhat misleading, because the "flattening" part plays a relatively minor role here. The task of creating a separate entry for each Dependents, with a copy of its ancestor elements, is much more significant.

See if this works for you:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:template match="/Report_Data">
    <xsl:copy>
        <xsl:for-each select="Report_Entry/Dependents">
            <Report_Entry>
                <xsl:copy-of select="../Employee_ID | ../Name | ../Citizenship_Countries"/>
                <xsl:for-each select="../National_Identifiers/*">
                    <xsl:element name="National_Identifiers_{name()}">
                        <xsl:value-of select="."/>
                    </xsl:element>
                </xsl:for-each>
                <xsl:copy-of select="../Marital_Status"/>
                <xsl:for-each select="*">
                    <xsl:element name="Dependent_{name()}">
                        <xsl:value-of select="."/>
                    </xsl:element>
                </xsl:for-each>
            </Report_Entry>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

Upvotes: 0

Related Questions