Reordering multiple siblings based on a property - xslt

I want to produce an HTML file like this example:
English
En Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Nunc rutrum, eros sit amet ornare faucibus.
Français
Fr Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Nunc rutrum, eros sit amet ornare faucibus.
From the following example XML source, on which I have no control:
<?xml version="1.0" encoding="ISO-8859-1"?>
<content id="">
<header language="en">
<enabled>true</enabled>
<img src="http://i.stack.imgur.com/xGCNw.gif" />
<!-- more header-related elements -->
</header>
<header language="fr">
<enabled>false</enabled>
<img src="" />
<!-- more header-related elements -->
</header>
<html language="en" type="source">
<![CDATA[
<p>En Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<p>Nunc rutrum, eros sit amet ornare faucibus.</p>
]]>
</html>
<html language="fr" type="source">
<![CDATA[
<p>Fr Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<p>Nunc rutrum, eros sit amet ornare faucibus.</p>
]]>
</html>
</content>
So I wrote this XSLT to do it:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<h1>English</h1>
<hr/>
<xsl:for-each select="content/header">
<xsl:call-template name="header">
<xsl:with-param name="lang">en</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
<xsl:for-each select="content/html">
<xsl:call-template name="html">
<xsl:with-param name="lang">en</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
<hr/>
<h1>Français</h1>
<hr/>
<xsl:for-each select="content/header">
<xsl:call-template name="header">
<xsl:with-param name="lang">fr</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
<xsl:for-each select="content/html">
<xsl:call-template name="html">
<xsl:with-param name="lang">fr</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
</xsl:template>
<xsl:template name="header" match="*">
<xsl:param name='lang'/>
<xsl:if test="current()[#language=$lang]">
<xsl:if test="enabled[normalize-space(text())='true']">
<xsl:call-template name="image"/>
<!-- more header-related elements -->
</xsl:if>
</xsl:if>
</xsl:template>
<xsl:template name="image" match="*">
<xsl:if test="img[not(normalize-space(#src)='')]">
<xsl:copy-of select="img"/>
</xsl:if>
</xsl:template>
<xsl:template name="html" match="*">
<xsl:param name='lang'/>
<xsl:if test="current()[#language=$lang]">
<xsl:value-of select="node()" disable-output-escaping="yes" />
</xsl:if>
</xsl:template>
</xsl:stylesheet>
That said, my solution feels very verbose, but seems to enable useful composition and reutilization properties, which are two things very important to me, since I will need to transform lots of XML documents whose structure is similar to this example; and thus, if most of my XSLTs can reuse parts of other XSLTs, this will be very useful.
A few notes of interest:
Transformation speed is of no importance, although it might be interesting to learn more on this aspect.
The transformations will never need to handle XML documents which encode more than the 2 example languages (en and fr).
So I would like to learn if my solution looks either anti-idiomatic-or even plain wrong-to you, XSLT wranglers.

This transformation doesn't contain any conditional XSLT instructions or any named templates:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my" exclude-result-prefixes="my">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<my:langs>
<lang short="en">English</lang>
<lang short="fr">Français</lang>
</my:langs>
<xsl:variable name="vLangs" select="document('')/*/my:langs/*"/>
<xsl:template match="header">
<xsl:apply-templates select="node()|#*"/>
<hr/>
<xsl:apply-templates select=
"../html[#language=current()/#language]/text()"/>
</xsl:template>
<xsl:template match="header/#language">
<h1><xsl:value-of select="$vLangs[#short=current()]"/></h1>
</xsl:template>
<xsl:template match="header[enabled='true']/img[#src and not(#src='')]">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="html/text()">
<xsl:value-of select="." disable-output-escaping="yes"/>
</xsl:template>
<xsl:template match="html|text()"/>
</xsl:stylesheet>
when applied on the provided XML document:
<content id="">
<header language="en">
<enabled>true</enabled>
<img src="http://i.stack.imgur.com/xGCNw.gif" />
<!-- more header-related elements -->
</header>
<header language="fr">
<enabled>false</enabled>
<img src="" />
<!-- more header-related elements -->
</header>
<html language="en" type="source">
<![CDATA[
<p>En Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<p>Nunc rutrum, eros sit amet ornare faucibus.</p>
]]>
</html>
<html language="fr" type="source">
<![CDATA[
<p>Fr Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<p>Nunc rutrum, eros sit amet ornare faucibus.</p>
]]>
</html>
</content>
the wanted, correct result is produced:
<h1>English</h1>
<img src="http://i.stack.imgur.com/xGCNw.gif" />
<hr />
<p>En Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<p>Nunc rutrum, eros sit amet ornare faucibus.</p>
<h1>Français</h1>
<hr />
<p>Fr Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<p>Nunc rutrum, eros sit amet ornare faucibus.</p>
Do note:
The use of templates and pattern matching.
The use of <xsl:apply-templates>
The use of predicates both in the match pattern of the templates and for selecting the necessary node-list in <xsl:apply-templates>

That's how I would've wrote it:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my"
exclude-result-prefixes="my">
<xsl:output method="html" indent="yes"/>
<my:language-labels>
<lang code="en" label="English"/>
<lang code="fr" label="Francais"/>
</my:language-labels>
<xsl:template match="/*">
<xsl:apply-templates select="header"/>
</xsl:template>
<xsl:template match="header">
<xsl:variable name="curLang" select="#language"/>
<h1>
<xsl:value-of select="document('')/*/my:language-labels/lang[#code = $curLang]/#label"/>
</h1>
<hr/>
<xsl:copy-of select="img[not(normalize-space(#src) = '')][../enabled[normalize-space() = 'true']]"/>
<xsl:value-of select="../html[#language = $curLang]" disable-output-escaping="yes"/>
</xsl:template>
</xsl:stylesheet>
Your HTML sample looks broken, so I may be a little wrong. My result is:
<h1>English</h1>
<hr>
<img src="http://i.stack.imgur.com/xGCNw.gif">
<p>En Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<p>Nunc rutrum, eros sit amet ornare faucibus.</p>
<h1>Francais</h1>
<hr>
<p>Fr Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<p>Nunc rutrum, eros sit amet ornare faucibus.</p>
Notes:
Use predicates. It is a very powerful instrument.
Keep hardcoded data in one place if possible.
apply-templates it's not a mysterious tool but a very essential XSLT mechanism.
You can call normalize-space and other functions without actually passing an argument, if the argument you need is the context element.

Related

Matching and replacing a string in XSL

I am not an XSL expert. I need to match a string and replace it with URL. String should be of a form 2 letters + 8 digits, so something like VA12345678.
Here is what I have so far (I have XSL and HTML in the same file):
<xsl:variable name="fubar" select="'testing VA12345678'" />
<xsl:variable name="fubarNew">
<xsl:call-template name="replace">
<xsl:with-param name="in" select="$fubar" />
<xsl:with-param name="old" select="'regex will go here'" />
<xsl:with-param name="new" select="'<a href='/cs/page.asp?id=VA12345678'>VA12345678</a>" />
</xsl:call-template>
</xsl:variable>
<span><xsl:value-of select="$fubarNew" /></span>
fubarNew should look like testing VA12345678 with VA12345678 linked to /cs/page.asp?id=VA12345678.
How do I add regex in here?
Your question is very unclear.
If - as it seems - you want to replace every occurrence of a string in the form of ########## (2 upper-case ASCII characters followed by 8 digits) with an anchor element in the form of ##########, then consider the following example:
Input
<root>
<string>Lorem ipsum dolor sit amet, consectetuer ABC123 adipiscing elit.</string>
<string>Nam interdum ante quis VA12345678 erat pellentesque elementum. Ut molestie quam sit DT87654321 amet ligula.</string>
<string>In enim. XY55551234 Duis dapibus hendrerit quam.</string>
</root>
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="string">
<xsl:copy>
<xsl:analyze-string select="." regex="[A-Z]{{2}}\d{{8}}" >
<xsl:matching-substring>
<a href="/cs/page.asp?id={.}">
<xsl:value-of select="." />
</a>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="." />
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="UTF-8"?>
<root>
<string>Lorem ipsum dolor sit amet, consectetuer ABC123 adipiscing elit.</string>
<string>Nam interdum ante quis VA12345678 erat pellentesque elementum. Ut molestie quam sit DT87654321 amet ligula.</string>
<string>In enim. XY55551234 Duis dapibus hendrerit quam.</string>
</root>

XSLT - Applying multiple templates to the same element

Right now I'm using a replace template which converts <p></p> tags in a new line:
<xsl:template name="string-replace">
<xsl:param name="text" />
<xsl:param name="replace" />
<xsl:param name="by" />
<xsl:choose>
<xsl:when test="$text = '' or $replace = ''or not($replace)" >
<!-- Prevent this routine from hanging -->
<xsl:value-of select="$text" />
</xsl:when>
<xsl:when test="contains($text, $replace)">
<xsl:value-of select="substring-before($text,$replace)" />
<xsl:value-of select="$by" />
<xsl:call-template name="string-replace">
<xsl:with-param name="text" select="substring-after($text,$replace)" />
<xsl:with-param name="replace" select="$replace" />
<xsl:with-param name="by" select="$by" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
I use it like this:
<xsl:variable name="replaceString">
<xsl:call-template name="string-replace">
<xsl:with-param name="text" select="$data/description/text" />
<xsl:with-param name="replace" select="'<p></p>'" />
<xsl:with-param name="by" select="'
'" />
</xsl:call-template>
</xsl:variable>
The thing is that the client now requested that other HTML tags should be interpreted correctly. For example, I want to replace <br>, or to set the font to bold when I have something like <b>Hello</b> inside the text.
For the <br> replacement I wrote this snippet:
<xsl:template match="br">
<fo:block></fo:block>
</xsl:template>
And for the <b> replacement this one:
<xsl:template match="b">
<fo:inline font-weight="bold">
<xsl:apply-templates select="*|text()"/>
</fo:inline>
</xsl:template>
How can I apply multiple transformations to the same text?
A text sample might look like this: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce nisl neque, lobortis ac consequat eu, feugiat a erat. Morbi eget augue dolor. Pellentesque vel laoreet ex. <p></p>Quisque convallis nisl tellus, in rhoncus libero porttitor in. Cras nunc diam, condimentum in ornare ut, mattis in arcu. Nulla ultrices sapien ligula, vel volutpat risus pharetra sed. <br></b>Nunc quis arcu eu ex <b>cursus pellentesque</b> at eget augue.. So it's a string with markup, not an XML with p or b elements.

How to group heading level in XSL

I have an HTML of the following process.
<p class="Ahead">Heading 1</p>
<p class="txt">Lorem ipsum dolor sit amet, consectetuer adipiscing elit</p>
<p class="Bhead">Heading 1.1</p>
<p class="txt">Nibh euismod tincidunt ut laoreet dolore magna aliquam</p>
<p class="list">Investigationes demonstraverunt lectores legere</p>
<p class="Chead">Heading 1.1.1</p>
<p class="txt">Typi non habent claritatem insitam</p>
<p class="Bhead">Heading 1.2</p>
<p class="txt">Lorem ipsum dolor sit amet</p>
The heading is going on up to 5 levels. Different attributes are inbetween the heading.
The output should be follow below.
<section>
<section-title>Heading 1</section-title>
<p class="txt">Lorem ipsum dolor sit amet, consectetuer adipiscing elit</p>
<section>
<section-title>Heading 1.1</section-title>
<p class="txt">Nibh euismod tincidunt ut laoreet dolore magna aliquam</p>
<p class="list">Investigationes demonstraverunt lectores legere</P>
<section>
<section-title>Heading 1.1.1</section-title>
<p class="txt">Typi non habent claritatem insitam</p>
</section>
</section>
<section>
<section-title>Heading 1.2</section-title>
<p class="txt">Lorem ipsum dolor sit amet</p>
</section>
</section>
Thanks in advance.
This stylesheet uses XSLT 2.0 and was adapted from Michael Kay's XSLT 2.0 and XPath 2.0 Programmer's Reference.pdf, page 341-342.
When the stylesheet below is applied to your input XML (I have added a root node named root to your example input XML):
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:strip-space elements="*"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* , node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root">
<xsl:for-each-group select="*" group-starting-with="p[#class='Ahead']">
<xsl:choose>
<xsl:when test="self::p[#class='Ahead']">
<xsl:apply-templates select="." mode="group"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="p[#class='Ahead']|p[#class='Bhead']|p[#class='Chead']" mode="group">
<xsl:variable name="this_att" select="substring-before(#class, 'head')"/>
<xsl:variable name="next" select="concat(translate($this_att, 'ABCDEFGH', 'BCDEFGHI'), 'head')"/>
<xsl:element name="section">
<section-title><xsl:apply-templates/></section-title>
<xsl:for-each-group select="current-group() except ." group-starting-with="p[#class = $next]">
<xsl:apply-templates select="." mode="group"/>
</xsl:for-each-group>
</xsl:element>
</xsl:template>
<xsl:template match="p[not(ends-with(#class, 'head'))]" mode="group">
<xsl:copy-of select="current-group()"/>
</xsl:template>
</xsl:stylesheet>
it produces:
<?xml version="1.0" encoding="UTF-8"?>
<section>
<section-title>Heading 1</section-title>
<p class="txt">Lorem ipsum dolor sit amet, consectetuer adipiscing elit</p>
<section>
<section-title>Heading 1.1</section-title>
<p class="txt">Nibh euismod tincidunt ut laoreet dolore magna aliquam</p>
<p class="list">Investigationes demonstraverunt lectores legere</p>
<section>
<section-title>Heading 1.1.1</section-title>
<p class="txt">Typi non habent claritatem insitam</p>
</section>
</section>
<section>
<section-title>Heading 1.2</section-title>
<p class="txt">Lorem ipsum dolor sit amet</p>
</section>
</section>

Apply templates to elements within a paragraph of text?

If I were to have the following XML document...
<?xml version="1.0"?>
<document>
<title>Foobar</title>
<article>
Phasellus ultrices arcu suscipit velit laoreet eu dignissim
dolor pulvinar. Proin ac libero a diam laoreet iaculis nec eu risus.
<ref url="http://en.wikipedia.org/wiki/FooBar">Foobar</ref> potenti.
Duis placerat laoreet est nec fringilla. Quisque vitae semper erat.
</article>
</document>
...how would I translate the article element to the following?
<p>
Phasellus ultrices arcu suscipit velit laoreet eu dignissim
dolor pulvinar. Proin ac libero a diam laoreet iaculis nec eu risus.
Foobar potenti.
Duis placerat laoreet est nec fringilla. Quisque vitae semper erat.
</p>
Specifically, it's the ref to a translation I'm interested in, since it's embedded within a block of plain text.
If you build upon the standard XSTL Identity Transform, this is a straight-forward task, you just need a template to match a ref element and output an a element instead.
<xsl:template match="ref">
<a>
<xsl:apply-templates select="#*|node()"/>
</a>
</xsl:template>
And to replace the attribute, you then have another template
<xsl:template match="ref/#url">
<xsl:attribute name="href">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
Note that if your ref element was guaranteed to always have an url attribute, you could also simplify those two templates into just one, like this:
<xsl:template match="ref">
<a href="{#url}">
<xsl:apply-templates select="node()"/>
</a>
</xsl:template>
You would then add other templates to replace any other elements as required, such as article being changed to p, and also a template to not output the title element.
Here is the full XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/document">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="title" />
<xsl:template match="article">
<p>
<xsl:apply-templates />
</p>
</xsl:template>
<xsl:template match="ref">
<a>
<xsl:apply-templates select="#*|node()"/>
</a>
</xsl:template>
<xsl:template match="ref/#url">
<xsl:attribute name="href">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
When applied to your sample XML, the following is output
<p>
Phasellus ultrices arcu suscipit velit laoreet eu dignissim
dolor pulvinar. Proin ac libero a diam laoreet iaculis nec eu risus.
Foobar potenti.
Duis placerat laoreet est nec fringilla. Quisque vitae semper erat.
</p>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates select="document"/>
</xsl:template>
<xsl:template match="document">
<document>
<xsl:apply-templates/>
</document>
</xsl:template>
<xsl:template match="title">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="article">
<p>
<xsl:apply-templates/>
</p>
</xsl:template>
<xsl:template match="ref">
<a>
<xsl:attribute name="href">
<xsl:value-of select="#url"/>
</xsl:attribute>
<xsl:apply-templates/>
</a>
</xsl:template>
</xsl:stylesheet>

How do I wrap a set of items within <xml:choose>?

A <div> cannot be a child of <xml:choose>, but I only want <li>s to repeat — in other words, not their parent <div>s or <ul>s.
Below you'll find my sample input, XSLT, and sample desired output.
Input
<?xml version="1.0" encoding="utf-8" ?>
<Collection>
<Content>
<Html>
<root>
<news>
<title>Item 1</title>
<publication-date>2010-04-16</publication-date>
<article-content>
<p>Aliquam mollis porttitor auctor. Aenean laoreet justo sed ipsum lobortis eleifend. In ac mollis neque. Donec rutrum turpis vel quam mattis eu vestibulum arcu tincidunt.</p>
</article-content>
</news>
</root>
</Html>
</Content>
<Content>
<Html>
<root>
<news>
<title>Item 2</title>
<publication-date>2010-04-19</publication-date>
<article-content>
<p>Aliquam mollis porttitor auctor. Aenean laoreet justo sed ipsum lobortis eleifend. In ac mollis neque. Donec rutrum turpis vel quam mattis eu vestibulum arcu tincidunt.</p>
</article-content>
</news>
</root>
</Html>
</Content>
</Collection>
XSLT
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*" />
<xsl:template match="/Collection/Content" xml:space="preserve">
<div id="latest-news" class="module clear">
<h2>Latest News</h2>
<xsl:choose>
<xsl:when test="position() = 1">
<div id="featured-story">
<h3>
<a href="#tk">
<xsl:copy-of select="Html/root/news/title/node()" />
</a>
</h3>
<p class="publish-date">
<xsl:copy-of select="Html/root/news/publication-date/node()" />
</p>
<xsl:copy-of select="Html/root/news/article-content/node()" />
<p class="more">
Read more
</p>
</div>
</xsl:when>
<xsl:when test="position() > 1 and position() < 6">
<div id="summaries" class="column-1">
<ul>
<li>
<h3>
<a href="#tk">
<xsl:copy-of select="Html/root/news/title/node()" />
</a>
</h3>
<p class="publish-date">
<xsl:copy-of select="Html/root/news/publication-date/node()" />
</p>
<xsl:copy-of select="Html/root/news/article-content/node()" />
<p class="more">
Read more
</p>
</li>
</ul>
</div>
</xsl:when>
<xsl:otherwise>
<div id="links" class="column-2">
<ul>
<li>
<p class="publish-date">
<xsl:copy-of select="Html/root/news/publication-date/node()" />
</p>
<h3>
<a href="#tk">
<xsl:copy-of select="Html/root/news/title/node()" />
</a>
</h3>
<p class="more">
Read more
</p>
</li>
</ul>
</div>
</xsl:otherwise>
</xsl:choose>
</div>
</xsl:template>
</xsl:stylesheet>
Output
<div id="latest-news" class="module clear">
<h2>Latest News</h2>
<div id="featured-story">
<h3>[Item 1]</h3>
<p class="publish-date">July 7, 2010</p>
<p>[Article content, in form of an extended summary]</p>
<p class="more">
Read more
</p>
</div>
<div id="summaries" class="column-1">
<ul>
<li>
<h3>[Item 2]</h3>
<p class="publish-date">July 7, 2010</p>
<p>[Article content, in short summary format]</p>
</li>
<li>
<h3>[Item 3 and so on]</h3>
<p class="publish-date">July 7, 2010</p>
<p>[Article content, in short summary format]</p>
</li>
</ul>
</div>
<div id="links" class="column-2">
<ul>
<li>
<h3>[Item 6]</h3>
<p class="publish-date">July 7, 2010</p>
</li>
<li>
<h3>[Item 7 and so on]</h3>
<p class="publish-date">July 7, 2010</p>
</li>
</ul>
</div>
</div>
Your structure is wrong. Here's a syntactically valid (but untested) refactoring. I didn't test since you didn't post some input XML, but I think this is what you want.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:template match="/Collection" xml:space="preserve">
<div id="latest-news" class="module clear">
<h2>Latest News</h2>
<div id="featured-story">
<h3>
<a href="#tk">
<xsl:copy-of select="Content[1]/Html/root/news/title/node()"/>
</a>
</h3>
<p class="publish-date">
<xsl:copy-of select="Content[1]/Html/root/news/publication-date/node()"/>
</p>
<xsl:copy-of select="Content[1]/Html/root/news/article-content/node()"/>
<p class="more">
Read more
</p>
</div>
<div id="summaries" class="column-1">
<ul>
<xsl:apply-templates select="Content[position() > 1 and position() < 6]"/>
</ul>
</div>
<div id="links" class="column-2">
<ul>
<xsl:apply-templates select="Content[position() > 5]"/>
</ul>
</div>
</div>
</xsl:template>
<xsl:template match="Content" xml:space="preserve">
<li>
<h3>
<a href="#tk">
<xsl:copy-of select="Html/root/news/title/node()"/>
</a>
</h3>
<p class="publish-date">
<xsl:copy-of select="Html/root/news/publication-date/node()"/>
</p>
<xsl:copy-of select="Html/root/news/article-content/node()"/>
<p class="more">
Read more
</p>
</li>
</xsl:template>
</xsl:stylesheet>
This stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*" />
<xsl:template match="Collection">
<div id="latest-news" class="module clear">
<h2>Latest News</h2>
<div id="featured-story">
<xsl:apply-templates select="Content[1]"/>
</div>
<div id="summaries" class="column-1">
<ul>
<xsl:apply-templates select="Content[position() > 1 and 6 > position()]"/>
</ul>
</div>
<div id="links" class="column-2">
<ul>
<xsl:apply-templates select="Content[position() > 5]"/>
</ul>
</div>
</div>
</xsl:template>
<xsl:template match="Content[position() != 1]">
<li>
<xsl:apply-templates/>
</li>
</xsl:template>
<xsl:template match="news">
<xsl:apply-templates/>
<p class="more">
Read more
</p>
</xsl:template>
<xsl:template match="Content[position() > 5]/*/*/news">
<xsl:apply-templates select="title|publication-date" />
</xsl:template>
<xsl:template match="title">
<h3>
<a href="#tk">
<xsl:value-of select="." />
</a>
</h3>
</xsl:template>
<xsl:template match="publication-date">
<p class="publish-date">
<xsl:value-of select="." />
</p>
</xsl:template>
<xsl:template match="article-content">
<p>
<xsl:value-of select="substring(.,1,15)" />
</p>
</xsl:template>
<xsl:template match="Content[1]/*/*/*/article-content">
<xsl:copy-of select="node()" />
</xsl:template>
</xsl:stylesheet>
Input:
<Collection>
<Content>
<Html>
<root>
<news>
<title>Item 1</title>
<publication-date>2010-04-13</publication-date>
<article-content>
<p>Aliquam mollis porttitor auctor. Aenean laoreet justo sed ipsum lobortis eleifend. In ac mollis neque. Donec rutrum turpis vel quam mattis eu vestibulum arcu tincidunt.</p>
</article-content>
</news>
</root>
</Html>
</Content>
<Content>
<Html>
<root>
<news>
<title>Item 2</title>
<publication-date>2010-04-14</publication-date>
<article-content>
<p>Aliquam mollis porttitor auctor. Aenean laoreet justo sed ipsum lobortis eleifend. In ac mollis neque. Donec rutrum turpis vel quam mattis eu vestibulum arcu tincidunt.</p>
</article-content>
</news>
</root>
</Html>
</Content>
<Content>
<Html>
<root>
<news>
<title>Item 3</title>
<publication-date>2010-04-15</publication-date>
<article-content>
<p>Aliquam mollis porttitor auctor. Aenean laoreet justo sed ipsum lobortis eleifend. In ac mollis neque. Donec rutrum turpis vel quam mattis eu vestibulum arcu tincidunt.</p>
</article-content>
</news>
</root>
</Html>
</Content>
<Content>
<Html>
<root>
<news>
<title>Item 4</title>
<publication-date>2010-04-16</publication-date>
<article-content>
<p>Aliquam mollis porttitor auctor. Aenean laoreet justo sed ipsum lobortis eleifend. In ac mollis neque. Donec rutrum turpis vel quam mattis eu vestibulum arcu tincidunt.</p>
</article-content>
</news>
</root>
</Html>
</Content>
<Content>
<Html>
<root>
<news>
<title>Item 5</title>
<publication-date>2010-04-17</publication-date>
<article-content>
<p>Aliquam mollis porttitor auctor. Aenean laoreet justo sed ipsum lobortis eleifend. In ac mollis neque. Donec rutrum turpis vel quam mattis eu vestibulum arcu tincidunt.</p>
</article-content>
</news>
</root>
</Html>
</Content>
<Content>
<Html>
<root>
<news>
<title>Item 6</title>
<publication-date>2010-04-18</publication-date>
<article-content>
<p>Aliquam mollis porttitor auctor. Aenean laoreet justo sed ipsum lobortis eleifend. In ac mollis neque. Donec rutrum turpis vel quam mattis eu vestibulum arcu tincidunt.</p>
</article-content>
</news>
</root>
</Html>
</Content>
<Content>
<Html>
<root>
<news>
<title>Item 7</title>
<publication-date>2010-04-19</publication-date>
<article-content>
<p>Aliquam mollis porttitor auctor. Aenean laoreet justo sed ipsum lobortis eleifend. In ac mollis neque. Donec rutrum turpis vel quam mattis eu vestibulum arcu tincidunt.</p>
</article-content>
</news>
</root>
</Html>
</Content>
</Collection>
Result:
<div id="latest-news" class="module clear">
<h2>Latest News</h2>
<div id="featured-story">
<h3>
Item 1
</h3>
<p class="publish-date">2010-04-13</p>
<p>Aliquam mollis porttitor auctor. Aenean laoreet justo sed ipsum lobortis eleifend. In ac mollis neque. Donec rutrum turpis vel quam mattis eu vestibulum arcu tincidunt.</p>
<p class="more">
Read more
</p>
</div>
<div id="summaries" class="column-1">
<ul>
<li>
<h3>
Item 2
</h3>
<p class="publish-date">2010-04-14</p>
<p>Aliquam mollis </p>
<p class="more">
Read more
</p>
</li>
<li>
<h3>
Item 3
</h3>
<p class="publish-date">2010-04-15</p>
<p>Aliquam mollis </p>
<p class="more">
Read more
</p>
</li>
<li>
<h3>
Item 4
</h3>
<p class="publish-date">2010-04-16</p>
<p>Aliquam mollis </p>
<p class="more">
Read more
</p>
</li>
<li>
<h3>
Item 5
</h3>
<p class="publish-date">2010-04-17</p>
<p>Aliquam mollis </p>
<p class="more">
Read more
</p>
</li>
</ul>
</div>
<div id="links" class="column-2">
<ul>
<li>
<h3>
Item 6
</h3>
<p class="publish-date">2010-04-18</p>
</li>
<li>
<h3>
Item 7
</h3>
<p class="publish-date">2010-04-19</p>
</li>
</ul>
</div>
</div>
Note: This way you get exactly what you want. "Pattern matching" your input in your templates you can express better your desired output and add possibility of reusability and maintenance.
Edit: Minor change in order to emphasize "pattern matching".