Search code examples
xmlxsltbi-publisherjdeenterpriseone

How to Restructure XML using XSLT when the Child Node is actually the Parent


I have a very poorly structured XML source coming out of our ERP system, and the Parent/Child relationship for Header to Detail is reversed because at the runtime, the parent (key) isn't known until the first detail record is process. This is due to the way the interface from an old DB2 mainframe application was written. Unfortunately, I am not at liberty to modify the report, nor do I have any sway to getting the report changed, so I have to deal with the source as is.

Here is what the XML output looks like:

<report>
    <detail>
        <header>
            <keyfield>1231</keyfield>
            <headerfield1>foo</headerfield>
            <headerfield2>bar</headerfield2>
        </header>
        <keymatch>1231</keymatch>
        <detailfield0>Line1</detailfield0>
        <detailfield1>this is bad structure</detailfield1>
        <detailfield2>and not my design</detailfield2>
    </detail>
    <detail>
        <keymatch>1231</keymatch>
        <detailfield0>Line2</detailfield0>
        <detailfield1>this is bad structure</detailfield1>
        <detailfield2>and not my design</detailfield2>
    </detail>
    <detail>
        <keymatch>1231</keymatch>
        <detailfield0>Line3</detailfield0>
        <detailfield1>this is bad structure</detailfield1>
        <detailfield2>and not my design</detailfield2>
    </detail>
    <detail>
        <keymatch>1231</keymatch>
        <detailfield0>Line4</detailfield0>
        <detailfield1>this is bad structure</detailfield1>
        <detailfield2>and not my design</detailfield2>
    </detail>
    <detail>
        <keymatch>1231</keymatch>
        <detailfield0>Line5</detailfield0>
        <detailfield1>this is bad structure</detailfield1>
        <detailfield2>and not my design</detailfield2>
    </detail>
    <detail>
        <header>
            <keyfield>1232</keyfield>
            <headerfield1>boo</headerfield>
            <headerfield2>far</headerfield2>
        </header>
        <keymatch>1232</keymatch>
        <detailfield0>Line1</detailfield0>
        <detailfield1>this is bad structure</detailfield1>
        <detailfield2>and not my design</detailfield2>
    </detail>
    <detail>
        <keymatch>1232</keymatch>
        <detailfield0>Line2</detailfield0>
        <detailfield1>this is bad structure</detailfield1>
        <detailfield2>and not my design</detailfield2>
    </detail>
    <detail>
        <keymatch>1232</keymatch>
        <detailfield0>Line3</detailfield0>
        <detailfield1>this is bad structure</detailfield1>
        <detailfield2>and not my design</detailfield2>
    </detail>
    <detail>
        <keymatch>1232</keymatch>
        <detailfield0>Line4</detailfield0>
        <detailfield1>this is bad structure</detailfield1>
        <detailfield2>and not my design</detailfield2>
    </detail>
    <detail>
        <keymatch>1232</keymatch>
        <detailfield0>Line5</detailfield0>
        <detailfield1>this is bad structure</detailfield1>
        <detailfield2>and not my design</detailfield2>
    </detail>
</report>

Ultimately, I need it to be in a format similar to the following:

<report>
    <header>
        <keyfield>1231</keyfield>
        <headerfield1>foo</headerfield>
        <headerfield2>bar</headerfield2>
            <detail>
                <keymatch>1231</keymatch>
                <detailfield0>Line1</detailfield0>
                <detailfield1>this is bad structure</detailfield1>
                <detailfield2>and not my design</detailfield2>
            </detail>
            <detail>
                <keymatch>1231</keymatch>
                <detailfield0>Line2</detailfield0>
                <detailfield1>this is bad structure</detailfield1>
                <detailfield2>and not my design</detailfield2>
            </detail>
            <detail>
                <keymatch>1231</keymatch>
                <detailfield0>Line3</detailfield0>
                <detailfield1>this is bad structure</detailfield1>
                <detailfield2>and not my design</detailfield2>
            </detail>
            <detail>
                <keymatch>1231</keymatch>
                <detailfield0>Line4</detailfield0>
                <detailfield1>this is bad structure</detailfield1>
                <detailfield2>and not my design</detailfield2>
            </detail>
            <detail>
                <keymatch>1231</keymatch>
                <detailfield0>Line5</detailfield0>
                <detailfield1>this is bad structure</detailfield1>
                <detailfield2>and not my design</detailfield2>
            </detail>
    </header>
    <header>
        <keyfield>1232</keyfield>
        <headerfield1>boo</headerfield>
        <headerfield2>far</headerfield2>
            <detail>
                <keymatch>1232</keymatch>
                <detailfield0>Line1</detailfield0>
                <detailfield1>this is bad structure</detailfield1>
                <detailfield2>and not my design</detailfield2>
            </detail>
            <detail>
                <keymatch>1232</keymatch>
                <detailfield0>Line2</detailfield0>
                <detailfield1>this is bad structure</detailfield1>
                <detailfield2>and not my design</detailfield2>
            </detail>
            <detail>
                <keymatch>1232</keymatch>
                <detailfield0>Line3</detailfield0>
                <detailfield1>this is bad structure</detailfield1>
                <detailfield2>and not my design</detailfield2>
            </detail>
            <detail>
                <keymatch>1232</keymatch>
                <detailfield0>Line4</detailfield0>
                <detailfield1>this is bad structure</detailfield1>
                <detailfield2>and not my design</detailfield2>
            </detail>
            <detail>
                <keymatch>1232</keymatch>
                <detailfield0>Line5</detailfield0>
                <detailfield1>this is bad structure</detailfield1>
                <detailfield2>and not my design</detailfield2>
            </detail>
    </header>
</report>

Admittedly, I don't know much about XSLT but I'm a quick study, and I've figured out that this is the tool that I need to use. For what it's worth, this is JD Edwards 9.1, and I'll be using BI Publisher to send the data through an XSL Template for further handoff to an EDI Partner.

Thanks,

Justin


Solution

  • Try it this way:

    XSLT 2.0

    <xsl:stylesheet version="2.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">
        <xsl:copy>
            <xsl:for-each-group select="detail" group-starting-with="detail[header]">
                <header>
                    <xsl:copy-of select="header/*"/>
                    <xsl:apply-templates select="current-group()"/>
                </header>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="detail">
        <xsl:copy>
            <xsl:copy-of select="* except header"/>
        </xsl:copy>
    </xsl:template>
    
    </xsl:stylesheet>