Reputation: 33
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)) > 1">
<xsl:value-of select="concat(substring($return,1,$width - 1), ' ')"/>
<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
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="' 	 '"/>
</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
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