Home > database >  Creating an XSL transformation to flatten an XML file so that all nested nodes move to the top level
Creating an XSL transformation to flatten an XML file so that all nested nodes move to the top level

Time:03-17

Essentially I need the entire contents of the XML file to reside in the root node, so I would need to change:

 <?xml version="1.0" encoding="UTF-8"?>
 <sss>
   <ss id="01.20211160392320">
     <idenSS>
       <numSS>
         <list>01</list>
         <seqOper>20211160392320</seqOper>
       </numSS>
     </idenSS>
   </ss>
</sss>

to something like this:

<?xml version="1.0" encoding="UTF-8"?>
<sss>
  <sss_ss_idenSS_numSS_list>01</sss_ss_idenSS_numSS_list>
  <sss_ss_idenSS_numSS_seqOper>20211160392320</sss_ss_idenSS_numSS_seqOper>
</sss>

The only way I've been able to come up with is extremely manual, and the XML I'm working with is extremely long, so I'd like to build it in a somewhat dynamic way, rather than explicitly naming the new tags.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" />
<xsl:template match="/">
        <sss>
          <sss_ss_idenSS_numSS_list>
             <xsl:value-of select="sss/ss/idenSS/numSS/list"/>
          </sss_ss_idenSS_numSS_list>
          <sss_ss_idenSS_numSS_seqOper>
             <xsl:value-of select="sss/ss/idenSS/numSS/seqOper"/>
          </sss_ss_idenSS_numSS_seqOper>
       </sss>
</xsl:template>
</xsl:stylesheet>

CodePudding user response:

I am not quite sure what in your example is constant and what can change. Here is something completely generic. The more specific you can make it, the more efficient it will become.

XSLT 1.0

<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="/*">
    <xsl:copy>
        <xsl:for-each select="//*[not(*)]">
            <xsl:variable name="name">
                <xsl:for-each select="ancestor-or-self::*">
                    <xsl:value-of select="name()"/>
                    <xsl:if test="position() != last()">-</xsl:if>
                </xsl:for-each>    
            </xsl:variable>
            <xsl:element name="{$name}">
                <xsl:value-of select="."/>
            </xsl:element>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>
  • Related