OASIS Mailing List ArchivesView the OASIS mailing list archive below
or browse/search using MarkMail.

 


Help: OASIS Mailing Lists Help | MarkMail Help

docbook-apps message

[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]


Subject: Printing formatted text with XSLT (solution)


It seems that printing well formatted text with XSL is a perennial
problem. So for the record, here is a solution Ive been using to print
docbooks (but should work for just about anything).

This stylesheet does left margin padding, width limitation, and stops
strings from breaking in midline due to existing newlines. See
comments for more info.

----- BEGIN text_format.xsl -----
<?xml version="1.0"?>
<!DOCTYPE stylesheet [
<!ENTITY space "&#32;">
<!ENTITY cr "&#13;">
<!ENTITY tab "&#9;">
<!ENTITY newln "&#10;">
]>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="1.0">

<!--
Breaks string on whitespace. If there is no white space to break on, like
in the case of a very long url, the word is wrapped.

USAGE

Main entry point is template 'format'.
Format requires 3 parameters
 txt : text to format
 space-padding : spaces to insert as left margin padding
 width : maximum width of text, including left margin padding

For a simple demonstration, call `xsltproc text_format.xsl source.xml | more`
to print out all source.xml text in a narrow column.

For practical usage, include this file in your stylesheet with

 <xsl:include href="text_format.xsl"/>

and call the format template with something like

 <xsl:template match="p">
   <xsl:call-template name="format">
     <xsl:with-param name="txt" source="normalize-space(.)">
     <xsl:with-param name="width" select="50"/>
     <xsl:with-param name="space-padding">20</xsl:with-param>
   </xsl:call-template>
   <xsl:text>&newln;</xsl:text>
 </xsl:template>

HISTORY

Origional source from http://www.dpawson.co.uk/xsl/sect2/N7240.html#d9312e307

dyssident modified 2006/02/03
 use translate() to avoid breaking before intended end of line
 take space-padding into account when applying width limit
 added simple test
 added documentation
-->

<!--
 Testing code
 Formats all text in source file if this stylesheet is used directly
-->
<xsl:template match="text()">
 <xsl:call-template name="format">
   <xsl:with-param name="txt" select="normalize-space(.)"/>
   <xsl:with-param name="width" select="50"/>
   <xsl:with-param name="space-padding">10</xsl:with-param>
 </xsl:call-template>
 <xsl:text>&newln;</xsl:text>
</xsl:template>

<!--
 This template is the main entry point for text formatting
 txt: text to process
 width: maximum text width
 space-padding: number of padding spaces in left margin
-->
<xsl:template name="format">
 <xsl:param name="txt" />
 <xsl:param name="width" />
 <xsl:param name="space-padding" />

 <!-- get left margin 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">

   <!-- real-width determines how man chars our line will contain -->
   <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" />
       <xsl:with-param name="def" select="$width" />
       <xsl:with-param name="space-padding" select="$space-padding" />
     </xsl:call-template>
  </xsl:variable>

  <!-- BEGIN output -->
  <!-- left margin padding  -->
  <xsl:value-of select="$space-pad" />
  <!-- translate() is used to remove newlines within the string we
will output -->
  <xsl:value-of select="translate(substring($txt, 1, $real-width),
'&newln;', '')" />
  <xsl:text>&newln;</xsl:text>
  <!-- END output -->

 <!-- iterate with rest of string -->
 <xsl:call-template name="format">
   <xsl:with-param name="txt" select="substring($txt,$real-width + 1)" />
   <xsl:with-param name="width" select="$width" />
   <xsl:with-param name="space-padding" select="$space-padding" />
 </xsl:call-template>

 </xsl:if>
</xsl:template>

<!--
 Determines position at which string will break
-->
<xsl:template name="tune-width">
 <xsl:param name="txt" />
 <xsl:param name="width" />
 <xsl:param name="def" />
 <xsl:param name="space-padding" />
 <!-- real-width decides width of string to output taking into
account space-padding -->
 <xsl:param name="real-width" select="$width - $space-padding"/>

 <!-- Find point at which string should break-->
 <xsl:choose>
   <!-- Just return default width if constraint is zero or string
width is less than constraint -->
   <xsl:when test="$real-width = 0 or string-length($txt)&lt;$real-width">
     <xsl:value-of select="$def" />
   </xsl:when>
   <xsl:otherwise>
     <xsl:choose>
       <!-- Look for whitespace to break on -->
       <xsl:when test="substring($txt, $real-width, 1 ) = ' '">
         <xsl:value-of select="$real-width" />
       </xsl:when>
       <xsl:otherwise>
         <!-- Decrement width and iterate tune-width looking for whitespace -->
         <xsl:call-template name="tune-width">
           <xsl:with-param select="$txt" name="txt" />
           <xsl:with-param select="$width - 1" name="width" />
           <xsl:with-param select="$def" name="def" />
           <xsl:with-param name="space-padding" select="$space-padding" />
         </xsl:call-template>
       </xsl:otherwise>
     </xsl:choose>
   </xsl:otherwise>
 </xsl:choose>
</xsl:template>

<!--
 Repeats 'repeat-chars' 'times' times.
 Used in margin spacing.
-->
<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:stylesheet>
----- END text_format.xsl -----


[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]