0

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>
kevin.b
  • 3
  • 2
  • What you describe and what you show are two very different things. Your output has exactly the same structure as the input; all that has changed are the element names. – michael.hor257k Mar 16 '22 at 21:57
  • Oops, you are 100% correct, I didn't get rid of the nesting. I've modified the desired output in edit. – kevin.b Mar 16 '22 at 22:03
  • OK, so where exactly are you stuck with this? And which version of XSLT can you use? – michael.hor257k Mar 16 '22 at 22:09
  • I'm not sure which versions are supported unfortunately, within this application I've only ever seen version 1.0 used so to be safe I'd say 1.0. My issue is that the only way of doing it is extremely manual. I'll add what I have so far to the post. – kevin.b Mar 16 '22 at 22:28
  • See here how to identify your processor and the version it supports: https://stackoverflow.com/a/25245033/3016153 – michael.hor257k Mar 16 '22 at 22:59

1 Answers1

0

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>
michael.hor257k
  • 113,275
  • 6
  • 33
  • 51
  • This is perfect, thank you so much. Could you just explain this part: select="//*[not(*)]" ? – kevin.b Mar 16 '22 at 23:26
  • `//*` selects all elements anywhere in the XML document. `[[not(*)]` restricts the selection to elements that do not have child elements - i.e. "leaf" nodes of the input tree. Read more: https://www.w3.org/TR/1999/REC-xpath-19991116/#path-abbrev – michael.hor257k Mar 17 '22 at 06:31