Could a call-template be written that took two parameters
?
a string, and a
number) return the string with empty spaces appended to the
end so that it
occupied the number of spaces specified by the number parameter?
So long as you know the number of spaces will never
exceed say 100, write
<xsl:template name="pad">
<xsl:param name="s"/>
<xsl:param name="len"/>
<xsl:variable name="spaces"> ... </xsl:variable>
<xsl:value-of select="substring(concat($s, $spaces),
1, $len)"/>
</xsl:template>
A more elegant solution, which handles any number of
spaces, is
for the template to append
one space to the string and then call itself to add
another "len-1", until len reaches zero.
You should check out XPath's string-handling functions.
Something like
<xsl:value-of
select="substring(concat($string, ' '), 1, 12))"/>
Always gives you a string twelve characters long, either
the first twelve
characters of $string, or $string padded out with spaces.
Variables can be also be
useful to make
things easier to read, reuse and maintain -- for example
<xsl:variable name="spacex12"
select="' '"/>
and then
<xsl:value-of select="substring(concat($string,
$spacex12), 1, 12))"/>
Example
Just as a challenge, I took it a little further. The
following outputs the
color values in this document
<test>
<color>red</color>
<color>blue</color>
<color>yellow</color>
</test>
at 12 characters each, right aligned:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:variable name="fieldWidth">12</xsl:variable>
<xsl:template match="color">
<xsl:variable name="valueLength"
select="string-length(normalize-space(.))"/>
<xsl:variable
name="padding"
select="$fieldWidth - $valueLength"/>
<xsl:text>[</xsl:text>
<xsl:value-of select="substring(' ',1,$padding)"/>
<xsl:value-of select="."/>
<xsl:text>]</xsl:text>
</xsl:template>
</xsl:stylesheet>
giving this output:
<?xml
version="1.0" encoding="utf-8"?>
[ red]
[ blue]
[ yellow]
for Fixed-length String Output
Here are the string padding functions that I use
frequently:
<xsl:template name="prepend-pad">
<!--
recursive template to right justify and prepend-->
<!-- the
value with whatever padChar is passed in
-->
<xsl:param name="padChar"> </xsl:param>
<xsl:param name="padVar"/>
<xsl:param name="length"/>
<xsl:choose>
<xsl:when test="string-length($padVar) <
$length">
<xsl:call-template name="prepend-pad">
<xsl:with-param name="padChar"
select="$padChar"/>
<xsl:with-param
name="padVar" select="concat($padChar,$padVar)"/>
<xsl:with-param name="length"
select="$length"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring($padVar,string-length($padVar) -
$length + 1)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="append-pad">
<!--
recursive template to left justify and append
-->
<!-- the
value with whatever padChar is passed in
-->
<xsl:param name="padChar"> </xsl:param>
<xsl:param name="padVar"/>
<xsl:param name="length"/>
<xsl:choose>
<xsl:when test="string-length($padVar) <
$length">
<xsl:call-template name="append-pad">
<xsl:with-param name="padChar"
select="$padChar"/>
<xsl:with-param name="padVar"
select="concat($padVar,$padChar)"/>
<xsl:with-param name="length"
select="$length"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring($padVar,1,$length)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Eg: to call the template from xsl variable or element
<ns39:elementname>
<xsl:call-template
name="prepend-padzero">
<xsl:with-param name="padChar" select="0"/>
<xsl:with-param name="padVar"
select="nsmpr5:InvoiceNumber"/>
<xsl:with-param
name="length" select="6"/>
</xsl:call-template>
<!-- <xsl:value-of
xml:id="id_754" select="concat
("AUT",nsmpr5:InvoiceNumber)"/> -->
</ns39: elementname
>
These will both ensure that the string ends up to be
whatever length you pass
in (ie. if the string is longer than expected it will
also truncate).
Pete Forman adds an option for left padding
Here's an example of padding on the left using a similar
technique.
It prints my size attribute to a width of 4.
<xsl:value-of select="substring(concat(' ', @size),
string-length(@size) + 1, 4)"/>
This is clearly not as versatile as some of the solutions
but it suffices for simple cases.
How to pad space to a text node to make it have specific
length
These are the templates I use to pad on the left or right
with any character passed in:
<xsl:template
name="prepend-pad">
<!-- recursive
template to right justify and prepend-->
<!-- the value
with whatever padChar is passed in
-->
<xsl:param
name="padChar"> </xsl:param>
<xsl:param
name="padVar"/>
<xsl:param
name="length"/>
<xsl:choose>
<xsl:when
test="string-length($padVar) < $length">
<xsl:call-template name="prepend-pad">
<xsl:with-param name="padChar"
select="$padChar"/>
<xsl:with-param name="padVar"
select="concat($padChar,$padVar)"/>
<xsl:with-param name="length"
select="$length"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of
select="substring($padVar,string-length($padVar) -
$length + 1)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template
name="append-pad">
<!-- recursive
template to left justify and append
-->
<!-- the value
with whatever padChar is passed in
-->
<xsl:param
name="padChar"> </xsl:param>
<xsl:param
name="padVar"/>
<xsl:param
name="length"/>
<xsl:choose>
<xsl:when
test="string-length($padVar) < $length">
<xsl:call-template name="append-pad">
<xsl:with-param name="padChar"
select="$padChar"/>
<xsl:with-param name="padVar"
select="concat($padVar,$padChar)"/>
<xsl:with-param name="length"
select="$length"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring($padVar,1,$length)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
The 'padChar' param passed in could be as many characters
as you want, actually. 'padVar'
is the variable to pad, and length is length,
obviously. Most of the XSLT I do is for fixed-length text
files, and these haven't failed me yet.