Recipe7.6.Wrapping Text to a Specified Width and Alignment


Recipe 7.6. Wrapping Text to a Specified Width and Alignment

Problem

You want to format multi-lined text within an XML document into a fixed-width-aligned format, insuring that lines wrap at word boundaries.

Solution

Here is a solution that handles both wrapping and alignment by reusing the text:justify template constructed in Recipe 7.3. For added flexibility, you can allow the alignment width to be specified separately from wrapping width, but default to it when unspecified:

<xsl:stylesheet version="1.0"    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"    xmlns:str="http://www.ora.com/XSLTCookbook/namespaces/strings"    xmlns:text="http://www.ora.com/XSLTCookbook/namespaces/text"    exclude-result-prefixes="text">     <xsl:include href="../strings/str.find-last.xslt"/> <xsl:include href="text.justify.xslt"/>     <xsl:template match="node( ) | @*" mode="text:wrap" name="text:wrap">   <xsl:param name="input" select="normalize-space( )"/>    <xsl:param name="width" select="70"/>   <xsl:param name="align-width" select="$width"/>   <xsl:param name="align" select=" 'left' "/>       <xsl:if test="$input">     <xsl:variable name="line">       <xsl:choose>         <xsl:when test="string-length($input) > $width">           <xsl:call-template name="str:substring-before-last">               <xsl:with-param name="input"                 select="substring($input,1,$width)"/>               <xsl:with-param name="substr" select=" ' ' "/>           </xsl:call-template>         </xsl:when>         <xsl:otherwise>           <xsl:value-of select="$input"/>         </xsl:otherwise>       </xsl:choose>     </xsl:variable>        <xsl:if test="$line">       <xsl:call-template name="text:justify">         <xsl:with-param name="value" select="$line"/>         <xsl:with-param name="width" select="$align-width"/>         <xsl:with-param name="align" select="$align"/>       </xsl:call-template>       <xsl:text>&#xa;</xsl:text>     </xsl:if>           <xsl:call-template name="text:wrap">       <xsl:with-param name="input"            select="substring($input, string-length($line) + 2)"/>       <xsl:with-param name="width" select="$width"/>       <xsl:with-param name="align-width" select="$align-width"/>       <xsl:with-param name="align" select="$align"/>     </xsl:call-template>   </xsl:if>      </xsl:template>

The solution reuses the str:substring-before-last template created in Recipe 2.4. The basic idea is to extract a line containing up to $width characters, extracting less if the line would not end in a space. The rest of the input is then processed recursively. The tricky part is to make sure that if a word with $width characters is encountered, you allow it to be split.

The following example shows how you can use this recipe to wrap and center some sample. It uses different alignment and wrapping widths to demonstrate the effect of these parameters:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"   xmlns:text="http://www.ora.com/XSLTCookbook/namespaces/text">       <xsl:include href="text.wrap.xslt"/>       <xsl:strip-space elements="*"/> <xsl:output method="text"/>       <xsl:template match="p">   <xsl:apply-templates select="." mode="text:wrap">     <xsl:with-param name="width" select="40"/>       <xsl:with-param name="align" select=" 'center' "/>     <xsl:with-param name="align-width" select="60"/>   </xsl:apply-templates>   <xsl:text>&#xa;</xsl:text> </xsl:template>       </xsl:stylesheet>

Input:

<doc>   <p>In the age of the Internet, formats such HTML, XHTML, and PDF clearly dominate  the application of XSL and XSLT. However, plain old text will never become obsolete  because it is the lowest common denominator in both human and machine-readable  formats.  XML is often converted to text to be imported into another application that  does not know how to read XML or does not interpret it the way you would prefer. Text  output is also used when the result will be sent to a terminal or post processed in a  Unix pipeline.</p>   <p>Many recipes in this section place stress on XSLT techniques that create very  generic XML to text converters. Here generic means that the transformation can easily  be customized to work on many different XML inputs or produce a variety of outputs or  both. The techniques employed in these recipes have application beyond specifics of a  given recipe and often beyond the domain of text processing. In particular, you may w ant to look at Recipe 7.2 through Recipe 7.5 even if they do not address a present need. </p> </doc>

Output:

             In the age of the Internet, formats                            such HTML, XHTML, and PDF clearly                           dominate the application of XSL and                           XSLT. However, plain old text will                        never become obsolete because it is the                      lowest common denominator in both human                        and machine-readable formats. XML is                        often converted to text to be imported                       into another application that does not                          know how to read XML or does not                          interpret it the way you would prefer.                         Text output is also used when the                           result will be sent to a terminal or                          post processed in a Unix pipeline.                                 Many recipes in this section place                         stress on XSLT techniques that create                         very generic XML to text converters.                             Here generic means that the                            transformation can easily be customized                      to work on many different XML inputs or                       produce a variety of outputs or both.                           The techniques employed in these                             recipes have application beyond                           specifics of a given recipe and often                        beyond the domain of text processing.                        In particular, you may want to look at                      Recipes Recipe 7.2 through Recipe 7.5 even if they do                            not address a present need.

Discussion

In many text-conversion scenarios, the final output device cannot handle text of arbitrary line length. Most devices (such as terminals) wrap the text that overflows its horizontal display area. This wrapping results in a sloppy-looking output. This example allows you to deal with fixed-width formatting more intelligently.

See Also

A similar text-wrapping template can be found in Jeni Tennison's XSLT and XPath on the Edge (M&T, 2001). However, this solution adds alignment capabilities and handles the case in which words are longer than the desired width.




XSLT Cookbook
XSLT Cookbook: Solutions and Examples for XML and XSLT Developers, 2nd Edition
ISBN: 0596009747
EAN: 2147483647
Year: 2003
Pages: 208
Authors: Sal Mangano

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net