Search code examples
xslt

XSLT moving nodes in a document and create the destination if necessary


I'm in a situation where I need to downgrade xml-documents from one version to another using XSLT. Being an XSLT-beginner I ran into trouble with this where I need to move information from one place to another:

<a>
  <b>123</b>
  <c>456</c>
</a>

Should transform into

<a>
  <d>
    <e>
      <b>123</b>
      <c>456</c>
    </e>
  </d>
</a>

Both b and c can occur 0 or 1 times. If neither of them are present in the original document, the d-node should not be created in the result. So <a><f>789</f></a> should remain unaffected.

Another example:

<a>
  <b>123</b>
  <f>789</f>
  <c>456</c>
</a>

Should transform to

<a>
  <d>
    <e>
      <b>123</b>
      <c>456</c>
    </e>
  </d>
  <f>789</f>
</a>

I have only tried XSLT version 1.0 so far, but using a newer version would work as well.

Would really appreciate some tips on how to solve this.


Solution

  • This will process correctly both your examples, but it's not clear if it is correct for all your possible cases.

    <xsl:stylesheet version="3.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    
    <xsl:mode on-no-match="shallow-copy"/>
    
    <xsl:template match="a[b or c]">
        <xsl:copy>
            <d>
                <e>
                    <xsl:apply-templates select="b | c"/>
                </e>
            </d>
            <xsl:apply-templates select="* except (b | c)"/>
        </xsl:copy>
    </xsl:template>
    
    </xsl:stylesheet>
    

    This is in XSLT 3.0.