Matching and replacing a string in XSL - xslt

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>

Related

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>

Reordering multiple siblings based on a property

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.

XSLT: Append spaces in "long" word

There is a code:
<p>
Lorem ipsum dolor sit ametconsecteturadipisicing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat.
Duis aute iruredolorinreprehenderit in voluptate
velit esse cillum doloreeufugiatnullapariatur. Excepteur sint
occaecat cupidatat non proident, sunt in culpa qui officia
deserunt mollit anim id est laborum.
</p>
It is necessary to receive:
<p>
Lorem ipsum dolor sit <span class="spaced">a m e t c o n s e c t e t u r a d i p i s i c i n g</span> elit,
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat.
Duis aute <span class="spaced">i r u r e d o l o r i n r e p r e h e n d e r i t</span> in voluptate
velit esse cillum <span class="spaced">d o l o r e e u f u g i a t n u l l a p a r i a t u r</span>. Excepteur sint
occaecat cupidatat non proident, sunt in culpa qui officia
deserunt mollit anim id est laborum.
</p>
The sense consists in dividing "long" words with spaces. To put space after each letter in such word. Then it is necessary to conclude this word in a tag with a class "spaced".
The word is considered "long" if the quantity of letters in this word is more 10 (for example. It is possible to set any value).
How to solve this problem means xslt?
Here is an XSLT 2.0 stylesheet that you could run with Saxon 9 or with AltovaXML tools:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xsd"
version="2.0">
<xsl:param name="l" as="xsd:integer" select="10"/>
<xsl:variable name="regex1" as="xsd:string" select="concat('\w{', $l, ',}')"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#*, node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="p/text()">
<xsl:analyze-string select="." regex="{$regex1}">
<xsl:matching-substring>
<span class="space">
<xsl:value-of select="for $ c in string-to-codepoints(.) return codepoints-to-string($c)"
separator=" "/>
</span>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
</xsl:stylesheet>
Very clever people have prompted me the decision, huge to them thanks. Works in xslt 1.0 without any extansions. It is not my solution.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml">
<xsl:output method="xml" media-type="text/xhtml" version="1" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" indent="yes" encoding="UTF-8" omit-xml-declaration="yes"/>
<xsl:template match="p">
<p>
<xsl:call-template name="tokens">
<xsl:with-param name="str" select="text()" />
</xsl:call-template>
</p>
</xsl:template>
<xsl:template name="tokens">
<xsl:param name="str" />
<xsl:choose>
<xsl:when test="contains($str, ' ')">
<xsl:call-template name="checklength">
<xsl:with-param name="str" select="substring-before($str, ' ')" />
</xsl:call-template>
<xsl:call-template name="tokens">
<xsl:with-param name="str" select="substring-after($str, ' ')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="checklength">
<xsl:with-param name="str" select="$str" />
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="checklength">
<xsl:param name="str" />
<xsl:choose>
<xsl:when test="string-length($str) > 10">
<span class="spaced">
<xsl:call-template name="insertspaces">
<xsl:with-param name="str" select="$str" />
</xsl:call-template>
</span>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$str" />
</xsl:otherwise>
</xsl:choose>
<xsl:text> </xsl:text>
</xsl:template>
<xsl:template name="insertspaces">
<xsl:param name="str" />
<xsl:choose>
<xsl:when test="string-length($str) > 1">
<xsl:value-of select="substring($str, 1, 1)" /><xsl:text> </xsl:text>
<xsl:call-template name="insertspaces">
<xsl:with-param name="str" select="substring($str, 2, string-length($str) - 1)" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$str" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>