Schpudd
Schpudd

Reputation: 33

XSLT 1.0: How can I format a paragraph over multiple lines whilst keeping a token intact?

I want to split a long sentence onto multiple lines whilst keeping the full word at the end of a sentence. I have a line length of 40, so it should print the current word then go on to the next line if it pushes the line length over 40. All the delimiters are spaces, and I am not currently retrieving the words as tokens. This seems extremely difficult as I am limited to using XSLT 1.0.

Example from:

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut mi neque, sit amet tincidunt magna. Phasellus eleifend suscipit neque, at pretium enim facilisis non. Aenean a ornare eros.

Desired example to:

Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Aenean ut mi neque, sit
amet tincidunt magna. Phasellus eleifend
suscipit neque, at pretium enim facilisis
non. Aenean a ornare eros.

Currently I am using an existing XSL method:

<xsl:template name="nextline">
    <xsl:param name="return"/>
    <xsl:param name="width"/>
    <xsl:choose>
        <!-- when the string-length is greater than the width -->
        <xsl:when test="(string-length($return) div string-length($width)) &gt; 1">
            <xsl:value-of select="concat(substring($return,1,$width - 1), '&#10;')"/>
            <xsl:call-template name="nextline">
                <xsl:with-param name="return" select="substring($return, $width)"/>
                <xsl:with-param name="width" select="$width"/>
            </xsl:call-template>
        </xsl:when>
        <!-- just print the string length -->
        <xsl:otherwise>
            <xsl:value-of select="substring($return,1,$width - 1)"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

Current, undesired, example to:

Lorem ipsum dolor sit amet, consectetur
 adipiscing elit. Aenean ut mi neque, s
it amet tincidunt magna. Phasellus elei
fend suscipit neque, at pretium enim fa
cilisis non. Aenean a ornare eros.

Partial solution below results in:

Lorem ipsum dolor sit amet, consectetur

adipiscing elit. Aenean ut mi neque, sit

amet tincidunt magna. Phasellus eleifend

suscipit neque, at pretium enim facilisis

non. Aenean a ornare eros.

Upvotes: 3

Views: 1867

Answers (2)

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243529

Here is a solution using the str-split-to-lines template from FXSL:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:f="http://fxsl.sf.net/">
 <xsl:import href="strSplit-to-Lines.xsl"/>

 <xsl:output indent="yes" omit-xml-declaration="yes"/>

 <xsl:template match="/">
  <xsl:call-template name="str-split-to-lines">
    <xsl:with-param name="pStr" select="concat(/*, ' ')"/>
    <xsl:with-param name="pLineLength" select="40"/>
    <xsl:with-param name="pDelimiters" select="' &#9;&#10;&#13;'"/>
  </xsl:call-template>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the following XML document:

<t>    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut mi neque, sit amet tincidunt magna. Phasellus eleifend suscipit neque, at pretium enim facilisis non. Aenean a ornare eros.</t>

the wanted, correct result is produced:

Lorem. ipsum dolor$ sit ame, consectetur 
adipiscing elit? Aenean ut mi neque, sit 
amet tincidunt magna. Phasellus eleifend 
suscipit neque, at pretium enim 
facilisis non. Aenean a ornare eros. 

Do note:

This solution allows any (multiple-valued) characters that are considered delimiters between words, to be specified as a parameter.

Upvotes: 1

Ian Roberts
Ian Roberts

Reputation: 122394

I would be tempted to use an extension function for this purpose rather than trying to code it in pure XSLT. You say in the question that you're using javax.xml.transform, which by default uses Xalan under the covers, which supports Java extension functions. Apache commons-lang 3.1 provides a static method WordUtils.wrap which appears to do exactly what you need, if you add that library to your project then you can call this as an extension as follows

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
     xmlns:wu="xalan://org.apache.commons.lang3.text.WordUtils"
     exclude-result-prefixes="wu">

  <xsl:template match=".....">
     <xsl:value-of select="wu:wrap(stringToWrap, 40)" />
  </xsl:template>
</xsl:stylesheet>

If you're getting the value to wrap from an element you may need to use the string function, i.e. wu:wrap(string(someElement), 40)

Upvotes: 2

Related Questions