[xsl] formatting lines to a fixed width.

Subject: [xsl] formatting lines to a fixed width.
From: Kamal Bhatt <kbhatt@xxxxxxxxx>
Date: Thu, 01 Dec 2005 16:43:11 +1100
Hi
My apologies for double posting this but I replied to a post accidentally, won't happen again.


I am outputting a field to plain text and I need to ensure that a fixed width is maintained. To help me with this I "borrowed" some code from www.dpawson.co.uk/xsl/sect2/N7240.html#d9312e433 . (BTW, if he is around, thanks to Mr. Pawson for maintaining this website, it has been a great resource).
I had to modify it, however, as it did not take two things into account. Firstly, it assumes that all lines need to be split, secondly it assumes a normalised string, that is, one without any newlines.


I fixed the first of these, but I am having problems with the second. Here is my modified version of the code. Basically, I assume that if the substring contains a newline then I should move through it in a forward direction until I find the newline. The ouput I am looking for is something like this:

title:[TAB]Blah BLah BLah <bold>blah</bold> blah blah blah
[TAB]
[TAB]BLAH BLAH
where [TAB] is replaced with a tab.

with input text:
<Text>Blah BLah BLah <bold>blah </bold>blah blah blah

BLAH BLAH</Text>

Also, if someone could explain where the bold tag goes when I run this, that would be appreciated.

<xsl:template name="text-print">
  <xsl:param name="txt"/>
  <xsl:param name="width"/>
  <xsl:param name="title"/>
  <xsl:param name="first"/>
  <xsl:param name="text-pos"/>
  <xsl:param name="space-padding"/>

  <xsl:param name="space-pad">
  <xsl:call-template name="repeat-chars">
      <xsl:with-param
       name="rep-chars"><xsl:text>&space;</xsl:text></xsl:with-param>
      <xsl:with-param name="times" select="$space-padding"/>
      <xsl:with-param name="str"></xsl:with-param>
  </xsl:call-template>
  </xsl:param>
  <xsl:if test="$txt">
  <xsl:variable name="real-width">
      <xsl:call-template name="tune-width">
      <xsl:with-param name="txt" select="$txt"/>
      <xsl:with-param name="width" select="$width - $space-padding"/>
      <xsl:with-param name="def" select="$width - $space-padding"/>
      </xsl:call-template>
  </xsl:variable>

  <xsl:choose>
      <xsl:when test="$first = 'true' and $text-pos = 1">
      <!-- TEXT OUTPUT BEGINS -->
      <xsl:value-of select="$title"/>:<xsl:text>&tab;</xsl:text>
      <xsl:value-of select="$space-pad"/>
      <xsl:value-of select="substring($txt, 1, $real-width)"/>
      <xsl:text>&newln;</xsl:text>
      <!-- TEXT OUTPUT ENDS -->
      </xsl:when>
      <xsl:otherwise>
      <!-- TEXT OUTPUT BEGINS -->
      <xsl:text>&tab;</xsl:text>
      <xsl:value-of select="$space-pad"/>
      <xsl:value-of select="substring($txt, 1, $real-width)"/>
      <xsl:text>&newln;</xsl:text>
      <!-- TEXT OUTPUT ENDS -->
      </xsl:otherwise>
  </xsl:choose>
  <xsl:call-template name="text-print">
      <xsl:with-param name="txt"
              select="substring($txt, $real-width + 1)"/>
      <xsl:with-param select="$width" name="width"/>
      <xsl:with-param name="first">false</xsl:with-param>
      <xsl:with-param name="title" select="$title"/>
      <xsl:with-param name="space-padding" select="$space-padding"/>
  </xsl:call-template>
 </xsl:if>
</xsl:template>

<xsl:template name="repeat-chars">
  <xsl:param name="rep-chars"/>
  <xsl:param name="times"/>
  <xsl:param name="str"/>
  <xsl:choose>
  <xsl:when test="$times &gt; 0">
      <xsl:call-template name="repeat-chars">
          <xsl:with-param name="rep-chars" select="$rep-chars"/>
      <xsl:with-param name="times" select="$times - 1"/>
      <xsl:with-param name="str" select="concat($str, $rep-chars)"/>
      </xsl:call-template>
  </xsl:when>
  <xsl:otherwise>
      <xsl:value-of select="$str"/>
  </xsl:otherwise>
  </xsl:choose>   </xsl:template>
<xsl:template name="tune-width">
   <xsl:param name="txt"/>
   <xsl:param name="width"/>
   <xsl:param name="def"/>

<xsl:variable name="newln"><xsl:text>&newln;</xsl:text></xsl:variable>

<xsl:variable name="space"><xsl:text>&space;</xsl:text></xsl:variable>
<xsl:if test="string-length($txt) &lt; $width">
<xsl:value-of select="string-length($txt)"/>
</xsl:if>


<xsl:if test="contains(substring($txt, 1, $width), $newln)">
<xsl:variable name="ret-width">
<xsl:call-template name="find-newline">
<xsl:with-param name="txt" select="$txt"/>
<xsl:with-param name="width">1</xsl:with-param>
<xsl:with-param name="def" select="$def"/>
</xsl:call-template> </xsl:variable> <xsl:value-of select="$ret-width"/> </xsl:if>


   <xsl:choose>
   <xsl:when test="$width = 0">
        <xsl:value-of select="$def"/>
   </xsl:when>
   <xsl:otherwise>
        <xsl:choose>
        <xsl:when test="substring($txt, $width, 1) = $space">
            <xsl:value-of select="$width"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:call-template name="tune-width">
             <xsl:with-param name="txt" select="$txt"/>
             <xsl:with-param name="width" select="$width - 1"/>
             <xsl:with-param name="def" select="$def"/>
            </xsl:call-template>
        </xsl:otherwise>
        </xsl:choose>
      </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template name="find-newline">
   <xsl:param name="txt"/>
   <xsl:param name="width"/>
   <xsl:param name="def"/>

<xsl:variable name="newln"><xsl:text>&newln;</xsl:text></xsl:variable>
<xsl:choose>
<xsl:when test="contains(substring($txt, $width, 1), $newln)">
<xsl:value-of select="$width"/>
</xsl:when> <xsl:otherwise>
<xsl:if test="$def=$width">
<xsl:value-of select="$def"/>
</xsl:if> <xsl:call-template name="find-newline">
<xsl:with-param name="txt" select="$txt"/>
<xsl:with-param name="width" select="$width + 1"/>
<xsl:with-param name="def" select="$def"/>
</xsl:call-template>
</xsl:otherwise> </xsl:choose>
</xsl:template>
Cheers.


Kamal

Current Thread