Padding in xslt

Padding Content

1. Padding
2. How to pad space to a text node to make it have specific length

1.

Padding

Mike Kay


> 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.

Wendell Piez adds

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))"/>

Bob DuCharme provides the 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]

Nate Austin adds, 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) &lt; $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) &lt; $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>

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.

2.

How to pad space to a text node to make it have specific length

Nate Austin

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) &lt; $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) &lt; $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.