Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
MortenWittrock
Active Contributor
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 post, 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 post: 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.
7 Comments
Labels in this area