XSLT 1.0 Greedy knapsack grouping methods? - xslt

I have an XML dataset (provided from SharePoint 2007 to a DVWP) structured something like:
<Rows>
<Row ID="1" Spanoffset="0" Span="55" Spantail="55"/>
<Row ID="2" Spanoffset="30" Span="31" Spantail="61"/>
<Row ID="3" Spanoffset="61" Span="20" Spantail="81"/>
<Row ID="4" Spanoffset="82" Span="30" Spantail="112"/>
</Rows>
Say each row represents a bar that starts at #Spanoffset and is #Span wide, #Spantail is there so I don't have to calculate it if I need it. I am trying to pack the rows together efficently so that rows that wont overlap get grouped together. The dataset is pre-sorted by #Spanoffset. This is essentially a knapsack problem as each Row could fit in multiple possible groups. What I want to do is a simple greedy solution, and know how I could code it in say c# or java, but since I cannot mark nodes as visited (well I can, but I lose it when I come back up the recursion tree) and I cannot seem to remove nodes as I visit them, I am at a loss for how to approach this.
For example the above data would look something like this:
<div style="clear:both">
<div style="width: 110px; margin-left: 0px; float:left;">1</div>
<div style="width: 40px; margin-left: 12px; float:left;">3</div>
<div style="width: 60px; margin-left: 2px; float:left;">4</div>
</div>
<div style="clear:both">
<div style="width: 62px; margin-left: 60px; float:left;">2</div>
</div>
I haven't been bothering trying to get the floats to work right as I have yet to be able to get the Row nodes to appear only one time each, in the right order. Once I get them there I am fairly certain I can get the formatting to work out.
The best XSLT I have come up with so far has been:
<xsl:template match="row">
<xsl:variable name="tail" select="#Spantail"/>
<div style="width:{2*#Span}px;
left:{2*(#Spanoffset)}px;">
<xsl:value-of select="#ID"/>
</div>
<xsl:apply-templates select="(following-sibling::row)[#Spanoffset>=$tail][1]"/>
</xsl:template>
Which generates
<div style="width: 110px;left: 0px">1</div>
<div style="width: 40px; left: 122px">3</div>
<div style="width: 60px; left: 164px">4</div>
<div style="width: 62px; left: 60px">2</div>
<div style="width: 40px; left: 122px">3</div>
<div style="width: 60px; left: 164px">4</div>
<div style="width: 40px; left: 122px">3</div>
<div style="width: 60px; left: 164px">4</div>
<div style="width: 60px; left: 164px">4</div>
So my problems are 2 (that I see) and I think they are intertwined.
1) How to fix/re-factor my template(s) to only emit each row once.
and
2) How to wrap the groupings in container <div> elements.
Been banging my head against this for 2 days, any one able to help?
Edit:
Well, after some sleep, I have the wrapping container by adding a boolean parameter to my template, and using some CDATA tags to emit <div> tags when its true. The boolean defaults to true, and when I call the nested apply-templates I set it to false, hence wrapping up the groups in containers. I still cant see a way of marking <Row>s as visited yet.

I think it's very tricky with just core XSLT, but it's easier with node-set(), a XSLT extension function:
<xsl:template name="add-row">
<xsl:param name="row"/>
<xsl:param name="prev-group" />
<xsl:if test="$row and not($row/#ID = $prev-group/Row/#ID)">
<xsl:copy-of select="$row" />
<xsl:call-template name="add-row">
<xsl:with-param name="row" select="$row/following-sibling::Row[#Spanoffset > $row/#Spantail][1]" />
<xsl:with-param name="prev-group" select="$prev-group" />
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="add-group">
<xsl:param name="first-row" />
<xsl:param name="prev-group" select="exsl:node-set(/)" />
<xsl:if test="$first-row">
<xsl:variable name="group">
<xsl:call-template name="add-row">
<xsl:with-param name="row" select="$first-row" />
<xsl:with-param name="prev-group" select="$prev-group" />
</xsl:call-template>
</xsl:variable>
<div clear="both">
<xsl:for-each select="exsl:node-set($group)/Row">
<div style="width: {2*#Span}px; left: {2*#Spanoffset}px"><xsl:value-of select="#ID"/></div>
</xsl:for-each>
</div>
<xsl:call-template name="add-group">
<xsl:with-param name="first-row" select="$first-row/following-sibling::Row[#Spanoffset < preceding-sibling::Row/#Spantail][1]" />
<xsl:with-param name="prev-group" select="exsl:node-set($group)" />
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template match="Rows">
<xsl:call-template name="add-group">
<xsl:with-param name="first-row" select="Row[1]" />
</xsl:call-template>
</xsl:template>
Don't forget to declare extension prefix and namespace in your stylesheet tag:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
extension-element-prefixes="exsl"
xmlns:exsl="http://exslt.org/common">
http://exslt.org/common is a valid namespace for Java XSLT processors, such as Xalan or Saxon; if you're using MSXML, use urn:schemas-microsoft-com:xslt instead.

Related

xsl 1.0 Why won't a node match return data

I'm using the following xml information:
<section>
<...>
</section>
<section>
<templateId root="2.16.840.1.113883.10.20.22.2.10" />
<text>
<table id="Appointments">
<tr>
<td id="heading">Appointments</td>
</tr>
<tr>
<td id="content">No future appointments scheduled.</td>
</tr>
</table>
<br />
<table id="Referrals">
<tr>
<td id="heading">Referrals</td>
</tr>
<tr>
<td id="content">No referrals available.</td>
</tr>
</table>
<br />
</text>
<section>
<section>
<...>
</section>
There are multiple section nodes (with their own child nodes, including templateId) within the document. I'm having trouble with this one so I wanted to be specific in the xml information.
and in my xslt file I want to get one particular table out. I'm referencing it the following way (I'm trying to use templates and I'm new to XSL so please bear with me)
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ms="urn:schemas-microsoft-com:xslt"
xmlns="http://www.w3.org/1999/xhtml">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="//section[templateId/#root='2.16.840.1.113883.10.20.22.2.17']/text/table[#id='Appointments']" />
</xsl: template>
<xsl:template match="section[templateId/#root='2.16.840.1.113883.10.20.22.2.17']/text/table[#id='Appointments']">
<div style="float: left; width: 50%;">
<span style="font-weight: bold;">
<xsl:value-of select="tr/td[#id='heading']"/>:
</span>
<br />
<xsl:call-template name="replace">
<xsl:with-param name="string" select="tr/td[#id='content']"/>
</xsl:call-template>
</div>
</xsl:template>
<xsl:template name="replace">
<xsl:param name="string"/>
<xsl:choose>
<xsl:when test="contains($string,'
')">
<xsl:value-of select="substring-before($string,'
')"/>
<br/>
<xsl:call-template name="replace">
<xsl:with-param name="string" select="substring-after($string,'
')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$string"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
In this particular xml example, the output should be:
Appointments:
No future appointments scheduled.
I'm thinking the match and select need some tweaking but not sure what part.
Also, if the template can be tweaked so that I could pass a parameter with the table/#id value so that I could reuse this one template for a couple of items,that would be even more beneficial (the output for referrals and appointments that are in this example would be the same).
Thanks for any help
This is your XML section root attribute (cut and paste from your XML):
root="2.16.840.1.113883.10.20.22.2.10"
This is your test XSL:
root='2.16.840.1.113883.10.20.22.2.17'
Of course they do not match, one ends with "10", the other with "17"
Changing the data to "17" and correcting the other errors in my comments yields:
<div style="float: left; width: 50%;"><span style="font-weight: bold;">Appointments:
</span><br>No future appointments scheduled.
</div

xslt 1.0 - Trying to get nodes for a specific value

I've got an XML file that has many similarly named nodes but attributes within certain nodes are unique. I want to output into an HTML page only the nodes that fall under a certain attribute value.
Here is the xml:
<document>
<component>
<section>
<templateId value="temp_1" />
<entry>
<act>
<code displayName="temp_1:code_1" />
</act>
</entry>
<entry>
<act>
<code displayName="temp_1:code_2" />
</act>
</entry>
<entry>
<act>
<code displayName="temp_1:code_3" />
</act>
</entry>
</section>
<section>
<templateId value="temp_2" />
<entry>
<act>
<code displayName="temp_2:code_1" />
</act>
</entry>
<entry>
<act>
<code displayName="temp_2:code_2" />
</act>
</entry>
</section>
</component>
</document>
From this specific example, I want to only get the displayName value from the section that has the templateId value of temp_2. This is the XSL code that I'm using but it is getting everything, not just the section that I want. i know the first "when" is working because the right header (between the span tags) is displaying properly. It's just the for-each through the entries.
<xsl:tempalte match="/">
<xsl:choose>
<xsl:when test="//templateId/#value='temp_2'">
<div style="margin-bottom: 5px; padding: 5px; border-bottom: 1px solid #000000;">
<span style="font-weight: bold;">Template 2: </span>
<br />
<xsl:choose>
<xsl:when test="count(//section/entry) != 0">
<xsl:for-each select="//section/entry">
<xsl:choose>
<xsl:when test="position() = 1">
<xsl:value-of select="act/code/#displayName" />
</xsl:when>
<xsl:otherwise>
<br/>
<xsl:value-of select="act/code/#displayName" />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
No codes to display
</xsl:otherwise>
</xsl:choose>
</div>
</xsl:when>
</xsl:choose>
</xsl:template>
It should display like so:
temp_2:code_1
<br>temp_2:code_2
Any help would be greatly appreciated.
I guess you want to completely restudy XSLT and its philosophy. Don't program it like it was BASIC. The basic pattern, at least for your case, is that an XSLT program is a collection of templates to handle matching elements. Instead of littering your code with if and choose, write templates with the proper matching conditions. Instead of BASIC's FOR I=1 TO 10, use <xsl:apply-templates/> to "iterate" over the children. Here's the basic idea:
<xsl:template match="/">
<html>
<xsl:apply-templates/>
</html>
</xsl:template>
<xsl:template match="templateId"/> <!-- skip templateID elements by default -->
<xsl:template match="templateId[#value='temp_2']">
<div style="margin-bottom: 5px; padding: 5px; border-bottom: 1px solid #000000;">
<span style="font-weight: bold;">Template 2: </span>
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="code">
<xsl:value-of select="#displayName"/>
<xsl:if test="position() != 1"><br/></xsl:if>
</xsl:template>
<xsl:template match="section[count(entry)=0]">
No codes to display
</xsl:template>
Why no template for act elements? Well, by default XSLT will provide you with a template which does a <xsl:apply-templates/>.
Based on your description it sounds like you only want the temp_2 values in your for-each.
That being the case you can just update your select to the following:
<xsl:for-each select="//section[templateId/#value = 'temp_2']/entry">
This says to grab any entry under section that has a templateId with an attribute of value that equals 'temp_2'.

get last item in content query web part using xslt (SharePoint 2010)

This is my first time that I am using Content Query Web part and xslt. I have to display the last 5 posts from a blog in the following fashion (please look at the image below):
The table contains two columns. In the left column I would like to display the last post and in the right column I would like to display the rest of the posts from a particual blog.
Edit 1
The source is just an OOTB Blog Site and I have added a few posts in it. I would like to display these posts in an html table which contains two columns. In the left column I would like to display the last post entered in the blog and in the right column I would like to loop through other posts. The user must specify how many posts he/she would like to see in the CQWP.
Edit 2
This is the xslt that I have created so far. The only think is that the table is being repeated multiple times, which I don't want that. There should be only one table. If you look in the xslt code I have manually entered some text, like Test1, test 2... In their place I would like to display the rest of the blog posts.
<xsl:template name="Post" match="Row[#Style='Post']" mode="itemstyle">
<xsl:variable name="SafeLinkUrl">
<xsl:call-template name="OuterTemplate.GetSafeLink">
<xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="DisplayTitle">
<xsl:call-template name="OuterTemplate.GetTitle">
<xsl:with-param name="Title" select="#Title"/>
<xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
</xsl:call-template>
</xsl:variable>
<div>
<table width="100%" cellpadding="2" cellspacing="2" border="1">
<tr>
<td colspan="2" valign="top">
<xsl:value-of select="#Author"/></td>
<td rowspan="2" valign="top" width="30%">
<div>
<b>Previous blog posts:</b>
</div>
<div>
<ul style="margin-left:-2px;">
<li>Test 1</li>
<li>Test 2</li>
<li>Test 3</li>
<li>Test 4</li>
</ul>
</div>
</td>
</tr>
<tr>
<td width="15%" valign="top">
image</td>
<td valign="top">
<div>
<xsl:value-of select="#Title"/>
</div>
<div class="custom_description">
<xsl:value-of select="#Body" disable-output-escaping="yes" />
</div>
<p>
<xsl:call-template name="OuterTemplate.CallPresenceStatusIconTemplate"/>
<a href="{$SafeLinkUrl}">
<xsl:if test="$ItemsHaveStreams = 'True'">
<xsl:attribute name="onclick">
<xsl:value-of select="#OnClickForWebRendering"/>
</xsl:attribute>
</xsl:if>
<xsl:if test="$ItemsHaveStreams != 'True' and #OpenInNewWindow = 'True'">
<xsl:attribute name="onclick">
<xsl:value-of disable-output-escaping="yes" select="$OnClickTargetAttribute"/>
</xsl:attribute>
</xsl:if>
<br />
<b>Read More ></b>
</a>
</p>
</td>
</tr>
</table>
</div>
</xsl:template>
Edit 3
<root>
<Posts>
<Post ID="1">
<Title>this post 1</Title>
<Body>The comment comes here</Body>
</Post>
<Post ID="2">
<Title>this post 2</Title>
<Body>The comment comes here</Body>
</Post>
<Post ID="3">
<Title>this post 3</Title>
<Body>The comment comes here</Body>
</Post>
<Post ID="4">
<Title>this post 4</Title>
<Body>The comment comes here</Body>
</Post>
<Post ID="5">
<Title>this post 5</Title>
<Body>The comment comes here</Body>
</Post>
</Posts>
</root>
Thank you
First let me caveat emptor: I know nothing about SharePoint, and I do not have an installation of SharePoint installed. There is a StackExchange website which specialised in SharePoint questions, and this site may serve you better than SO. See https://sharepoint.stackexchange.com/questions/22465/recreating-the-blog-template
You should also take a look at http://www.glynblogs.com/2011/04/overriding-the-presentation-of-an-xslt-list-view-web-part.html .
UPDATE
This XSLT 1.0 style-sheet, for an MS XSLT processor...
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="xsl msxsl">
<xsl:output method="html" doctype-system="" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*" />
<xsl:variable name="empty-main">
<empty-main>No content yet.</empty-main>
</xsl:variable>
<xsl:variable name="empty-sub">
<empty-main>No older content yet.</empty-main>
</xsl:variable>
<xsl:template match="/*">
<html>
<head>
<title>Blog</title>
<style type="text/css">
table {
width: 100%;
border: 1px solid #000;
}
td.main-col, td.subsiduary-col {
vertical-align:text-top;
}
td.main-col {
width: 75%
}
td.subsiduary-col {
width: 25%
}
</style>
</head>
<body>
<table border="1">
<tr>
<xsl:variable name="count-posts" select="count(msxsl:node-set(Posts/Post))" />
<td class="main-col">
<xsl:apply-templates select="
(Posts/Post[last()] | msxsl:node-set($empty-main))[1]" />
</td>
<td class="subsiduary-col">
<xsl:apply-templates select="
Posts/Post[position() > last() - 5 and position() < last()] |
msxsl:node-set($empty-sub)[$count-posts < 2]" />
</td>
</tr>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="Post">
<xsl:apply-templates select="Title" />
<p><xsl:copy-of select="Body/node()" /></p>
</xsl:template>
<xsl:template match="Post[last()]/Title" priority="2">
<h1><xsl:value-of select="." /></h1>
</xsl:template>
<xsl:template match="Post/Title">
<h2><xsl:value-of select="." /></h2>
</xsl:template>
<xsl:template match="empty-main|empty-sub" priority="2">
<p><xsl:value-of select="." /></p>
</xsl:template>
</xsl:stylesheet>
...will transform this input...
<root>
<Posts>
<Post ID="1">
<Title>this post 1</Title>
<Body>The comment comes here</Body>
</Post>
<Post ID="2">
<Title>this post 2</Title>
<Body>The comment comes here</Body>
</Post>
<Post ID="3">
<Title>this post 3</Title>
<Body>The comment comes here</Body>
</Post>
<Post ID="4">
<Title>this post 4</Title>
<Body>The comment comes here</Body>
</Post>
<Post ID="5">
<Title>this post 5</Title>
<Body>The comment comes here</Body>
</Post>
</Posts>
</root>
..into this output...
<!DOCTYPE html SYSTEM "">
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Blog</title>
<style type="text/css">
table {
width: 100%;
border: 1px solid #000;
}
td.main-col, td.subsiduary-col {
vertical-align:text-top;
}
td.main-col {
width: 75%
}
td.subsiduary-col {
width: 25%
}
</style>
</head>
<body>
<table border="1">
<tr>
<td class="main-col">
<h1>this post 5</h1>
<p>The comment comes here</p>
</td>
<td class="subsiduary-col">
<h2>this post 1</h2>
<p>The comment comes here</p>
<h2>this post 2</h2>
<p>The comment comes here</p>
<h2>this post 3</h2>
<p>The comment comes here</p>
<h2>this post 4</h2>
<p>The comment comes here</p>
</td>
</tr>
</table>
</body>
</html>
For a visual of how this renders in a browser, paste the html output into http://htmledit.squarefree.com/ .
Displays the first or the last item depending on Sorting selected in the panel tool of the web part.
<xsl:if test="count(preceding-sibling::*)=0">
Example
<xsl:template name="DisplayPosts" match="Row[#Style='DisplayPosts']" mode="itemstyle">
<table width="100%" border="1">
<tr>
<td width="70%">
<xsl:if test="count(preceding-sibling::*)=0">
<xsl:value-of select="#Title" />
</xsl:if>
</td>
<td width="30%">
<xsl:if test="count(preceding-sibling::*)>0">
<xsl:value-of select="#Title" />
</xsl:if>
</td>
</tr>
</table>
</xsl:template>

XSLT transform of XML document to XHTML document

Here's my template:
<xsl:template name="rec">
<xsl:for-each select="*">
<div class="{local-name()}">
<xsl:for-each select="#*">
<xsl:attribute name="data-{local-name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:for-each>
<xsl:value-of select="text()" />
<xsl:call-template name="rec" />
</div>
</xsl:for-each>
</xsl:template>
Given a document like so:
<test>
<item value="1">Item 1 Text</item>
<item value="2">Item 2 Text</item>
</test>
The above transform will turn it into:
<div class="test">
<div class="item" data-value="1">Item 1 Text</div>
<div class="item" data-value="2">Item 2 Text</div>
</div>
The problem I'm having, is that this transform doesn't respect text nodes properly, and I don't have enough background with XSLT to figure out how to fix it. Here's the problem: given xml like so:
<para>This is a <emphasis>paragraph</emphasis> people!</para>
I would like to see the following output:
<div class="para">This is a <div class="emphasis">paragraph</div> people!</div>
The problem is that I'm not getting this - I'm getting this:
<div class="para">This is a <div class="emphasis">paragraph</div></div>
Notice the missing 'people!' text node. How can I fix my XSLT above to provide me with the output I need?
One problem is that
<xsl:value-of select="text()" />
just selects the value of the first child text node, and outputs it.
The easiest way to do this right is probably to use <xsl:apply-templates> instead of <xsl:call-template>.
Then instead of
<xsl:for-each select="*">
and
<xsl:value-of select="text()" />
you can use
<xsl:apply-templates />
which will apply the appropriate template to each child element and text node, in order, not skipping any.
Here is a complete implementation:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="*">
<div class="{local-name()}">
<xsl:for-each select="#*">
<xsl:attribute name="data-{local-name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:for-each>
<xsl:apply-templates />
</div>
</xsl:template>
</xsl:stylesheet>
Note the <xsl:apply-templates/>, which operates on all children of the context node, including text nodes, by default in absence of an explicit select attribute.
A default template is used for text nodes. This template simply copies them to the output.
Sample input:
<test>
<item value="1">Item 1 Text</item>
<item value="2">Item 2 Text</item>
<para>This is a <emphasis>paragraph</emphasis> people!</para>
</test>
produces the desired output:
<div class="test">
<div class="item" data-value="1">Item 1 Text</div>
<div class="item" data-value="2">Item 2 Text</div>
<div class="para">This is a <div class="emphasis">paragraph</div> people!</div>
</div>

master stylesheet sharing in XSLT

i would like to create a master template in XSLT, which could be stored in a separate file. Every other Page stylesheets share it, with xsl:import.
master.xslt
<xsl:template match="Page">
<html>
<head>
</head>
<body>
<call-template name="Content"/>
</body>
</html>
</xsl:template>
<xsl:stylesheet>
page.xslt
<xsl:stylesheet>
<xsl:import href="master.xslt"/>
<xsl:template match="/">
<apply-templates match="Page"/>
</xsl:template>
<xsl:template name="Content">
... apply something page-specific
</xsl:template>
</xsl:stylesheet>
page.xml
<Page>
... something page-specific
</Page>
Can i improve this solution?
i cannot start from master stylesheet, because i will need xsl:import everything.
i dont want master.xslt contain references on each particular page.
Another decision (which is against the xslt spirit) maybe such:
master.xslt
<xsl:template name="masterHead">
<html>
<head>
</head>
<body>
</xsl:template>
<xsl:template name=masterEnd>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
page.xslt
<xsl:stylesheet>
<xsl:import href="master.xslt"/>
<xsl:template match="/">
<call-template name=masterHead>
... apply something page-specific
<call-template name=masterEnd/>
</xsl:template>
</xsl:stylesheet>
we don't need any general root <Page> element.
Using <xsl:import> is the right design decision. This is exactly the main use-case this XSLT directive was intended for.
One can go further even more -- lookup for the <xsl:apply-imports> directive, and in addition to how an imported stylesheet can apply templates about whose actions and meaning it absolutely doesn't know anything. The latter is called Higher-Order-Functions and is implemented in XSLT with the FXSL library (written entirely in XSLT).
That looks about right to me... very common to what I have used in the past (although I've often used <xsl:include/>, but either should work). The main change I might make is to make the match more explicit (at least in the master xslt) - i.e.
<xsl:template match="/Page"> <!-- leading slash -->
so it won't accidentally match Page elements at other locations (for example, data-paging, like <Page Index="3" Size="20"/>).
One other common thing I do is to add a "*" match that uses xsl:message to throw an error if I don't have a more-specific match for a node. This makes it more obvious when you have a typo, etc.
I'm actually glad to have found this example as I've been looking for verification that this is actually the correct approach to a master/slave template setup.
However the examples provided did not work out of the box on tomcat - so just to help others who only knows how to copy paste here are a working tomcat set of master / slave files.
Master.xsl :
<?xml version="1.0" encoding="iso-8859-1" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="iso-8859-15" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" indent="no"/>
<!-- http://stackoverflow.com/questions/646878/master-stylesheet-sharing-in-xslt -->
<xsl:template match="ms247">
<html>
<head>
<title>test</title>
</head>
<body>
<div style="border: 1px solid black; width: 200px; float: left; margin: 10px; padding: 5px;">
<xsl:call-template name="left"/>
</div>
<div style="border: 1px solid black; width: 200px; float: left; margin: 10px; padding: 5px;">
<xsl:call-template name="content"/>
</div>
<div style="border: 1px solid black; width: 200px; float: left; margin: 10px; padding: 5px;">
<xsl:call-template name="right"/>
</div>
</body>
</html>
</xsl:template>
<xsl:template name="content">
<span style="color: red">Content template is empty - overrule in page template.</span>
</xsl:template>
<xsl:template name="left">
<span style="color: red">Left template is empty - overrule in page template.</span>
</xsl:template>
<xsl:template name="right">
<span style="color: red">Right template is empty - overrule in page template.</span>
</xsl:template>
</xsl:stylesheet>
And slave.xsl:
<?xml version="1.0" encoding="iso-8859-1" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="master.xsl"/>
<xsl:template name="content">
... apply something page-specific
</xsl:template>
<xsl:template name="right">
And we have RIGHT content!
<!-- Execute matching template which is NOT triggered automatically -->
<xsl:apply-templates select="params/param"/>
</xsl:template>
<!-- And we do not define any left template -->
<!-- Example -->
<xsl:template match="ms247/params/param">
Paramters on page: <xsl:value-of select="#name"/><br/>
</xsl:template>
</xsl:stylesheet>
Hope this can help others - do not be shy to drop me a note.