Monday 22 November 2021

xslt padding with characters call template for left pad and right pad

 

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) &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>

 

 

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 (&quot;AUT&quot;,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) &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.

No comments:

Post a Comment

xslt padding with characters call template for left pad and right pad

  Could a call-template be written that took two parameters ?   a string, and a   number) return the string with empty spaces appended t...