Skip to Content

Extensible Stylesheet Language Transformations, or XSLT for short, is a powerful language for writing XML transformations. With XSLT, you can create succint and elegant solutions to thorny XML mapping problems. The language has a number of cool tricks up its sleeve, and in this blog, I’m going to show you one of the lesser known ones: Stylesheet inheritance with the <xsl:import> declaration.

With this technique, you can solve mapping problems that would otherwise require you to make a copy of an existing stylesheet, and modify the copy. In other words: With stylesheet inheritance, you can uphold the Don’t Repeat Yourself (DRY) principle and avoid code duplication.

To start things off, let’s take a look at how you can include an XSLT stylesheet in another stylesheet.

Importing stylesheets

XSLT supports two ways of including a stylesheet in another stylesheet: <xsl:include> and <xsl:import>. Both declarations must be top-level elements in the stylesheet, i.e. children of the <xsl:stylesheet> element. However, <xsl:import> elements must always be the first child elements of <xsl:stylesheet>.

<xsl:include> and <xsl:import> are similar, but they differ in one area, which is central to the topic of this blog: When importing a stylesheet with <xsl:import>, templates defined in the importing stylesheet, has higher precedence than templates defined in the imported stylesheet.

What that means, is that a stylesheet that imports another stylesheet, can override the templates defined in the imported stylesheet. This lets us create a customised version of a stylesheet, changing only certain aspects of that stylesheet.

A concrete example

Let’s get a little more practical, and take a look at a concrete example. Here’s a simple stylesheet that creates a header, a footer and five <line> elements in between:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    
    <xsl:template match="/">
        <doc>
            <xsl:call-template name="header"/>
            <xsl:call-template name="lines"/>
            <xsl:call-template name="footer"/>
        </doc>
    </xsl:template>
    
    <xsl:template name="header">
        <header>
            <xsl:text>Header content goes here</xsl:text>
        </header>
    </xsl:template>

    <xsl:template name="lines">
        <lines>
            <xsl:for-each select="1 to 5">
                <xsl:variable name="linenum" select="."/>
                <xsl:call-template name="single-line">
                    <xsl:with-param name="linenum" select="$linenum"/>
                    <xsl:with-param name="content" select="concat('Line ', $linenum, ' content goes here')"/>
                </xsl:call-template>
            </xsl:for-each>
        </lines>
    </xsl:template>
    
    <xsl:template name="single-line">
        <xsl:param name="linenum"/>
        <xsl:param name="content"/>
        <line number="{$linenum}">
            <xsl:value-of select="$content"/>
        </line>
    </xsl:template>

    <xsl:template name="footer">
        <footer>
            <xsl:text>Footer content goes here</xsl:text>
        </footer>
    </xsl:template>
    
</xsl:stylesheet>

It generates the following output:

<?xml version="1.0" encoding="UTF-8"?>
<doc>
    <header>Header content goes here</header>
    <lines>
        <line number="1">Line 1 content goes here</line>
        <line number="2">Line 2 content goes here</line>
        <line number="3">Line 3 content goes here</line>
        <line number="4">Line 4 content goes here</line>
        <line number="5">Line 5 content goes here</line>
    </lines>
    <footer>Footer content goes here</footer>
</doc>

(For simplicity’s sake, this stylesheet always produces the same output, regardless of which document it is applied to.)

Now imagine that we want to make a slight change. In another integration scenario, we need the <line> element to look like this:

<line>
    <number>x</number>
    <content>Line x content goes here</content>
</line>

How can we achieve this? Well, we could make a copy of the original stylesheet, and then rewrite the single-line template to produce the desired output. That would work, obviously, but it’s not the best solution by far. All updates and fixes made to the original stylesheet would have to be applied to the copy as well. DRY, right?

Instead, let’s use the <xsl:import> declaration to import the stylesheet general.xsl into a second, smaller stylesheet, and then override the single-line template. Here’s the complete stylesheet:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    
    <xsl:import href="general.xsl"/>
    
    <xsl:template name="single-line">
        <xsl:param name="linenum"/>
        <xsl:param name="content"/>
        <line>
            <number>
                <xsl:value-of select="$linenum"/>
            </number>
            <content>
                <xsl:value-of select="$content"/>    
            </content>
        </line>
    </xsl:template>
    
</xsl:stylesheet>

This customised stylesheet produces the following output:

<?xml version="1.0" encoding="UTF-8"?>
<doc>
    <header>Header content goes here</header>
    <lines>
        <line>
            <number>1</number>
            <content>Line 1 content goes here</content>
        </line>
        <line>
            <number>2</number>
            <content>Line 2 content goes here</content>
        </line>
        <line>
            <number>3</number>
            <content>Line 3 content goes here</content>
        </line>
        <line>
            <number>4</number>
            <content>Line 4 content goes here</content>
        </line>
        <line>
            <number>5</number>
            <content>Line 5 content goes here</content>
        </line>
    </lines>
    <footer>Footer content goes here</footer>
</doc>

The <line> element has been updated according to the new requirement, but the rest of the output remains unchanged. Mission accomplished, without duplicated code!

Stylesheet inheritance in Cloud Integration

There’s not much to implementing the technique discussed here in Cloud Integration. Upload both stylesheets on the Resources tab of your integration flow, and add an XSLT Mapping step that uses the importing stylesheet. That’s it; CPI’s XSLT processor will take it from there.

To report this post you need to login first.

5 Comments

You must be Logged on to comment or reply to a post.

  1. Olegs Veliks

    Hello Morten.

     

    I have generic question – what are those requirements (based on your experience) when we should give preference to XSLT, instead of regular mapping?

    Did you faced any tasks when XML transformation can be solved only using XSLT? Thanks.

    (1) 
    1. Morten Wittrock Post author

      Hi Olegs

      That’s a very good question. I should probably expand on this in a separate blog, but let me give you a brief answer now. XSLT is particularly well suited for complex mappings, where the source and target structures are very different. XPath is at the core of XSLT, so compared to Message mapping, navigating XML structures, and implementing complex rules is incredibly easy. Message Mapping is easy to pick up and get started with, and for mappings that are not too complicated, it’s a very nice tool. However, complicated mappings can be really hard to implement in Message Mapping, and at the same time almost trivial in XSLT. That power comes at the cost of a quite steep learning curve, though.

      Regards,

      Morten

       

      (1) 
  2. Florian Kube

    Thank you Morten.

    It would be nice if it would be possible to add a folder or archive on the CPI. So it would be possible to organize the sub XSLT scripts.

    (1) 
    1. Morten Wittrock Post author

      Hi Florian

      The resource handling in WebUI has improved quite a lot over time, so I would definitely not rule something like that out. Let’s see what happens 🙂

      Regards,

      Morten

       

      (1) 

Leave a Reply