I was hoping to call ..
<xsl:call-template name="widow-fix">
<with-param name="text" select="text"></with-param>
</xsl:call-template>
And then it would look for the last space
in the text and replace it with #160;
when finalized.
Should be able to support
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
and
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
Please use a different character, like #
to answer/prove, so the result when I test would be
Lorem ipsum dolor sit amet, consectetur adipiscing#elit.
and
<p>Lorem ipsum dolor sit amet, consectetur adipiscing#elit.</p>
All that you need is to replace the last space in every text node:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="p | text()">
<xsl:apply-templates select="." mode="widow-fix"/>
</xsl:template>
<xsl:template match="* | @*">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="* | @*" mode="widow-fix">
<xsl:copy>
<xsl:apply-templates select="@* | node()" mode="widow-fix"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()[contains(., ' ')]" mode="widow-fix">
<xsl:call-template name="text">
<xsl:with-param name="text" select="."/>
</xsl:call-template>
</xsl:template>
<xsl:template name="text">
<xsl:param name="text"/>
<xsl:variable name="substring-before" select="substring-before($text, ' ')"/>
<xsl:variable name="substring-after" select="substring-after($text, ' ')"/>
<xsl:choose>
<xsl:when test="contains($substring-after, ' ')">
<xsl:value-of select="$substring-before"/>
<xsl:text> </xsl:text>
<xsl:call-template name="text">
<xsl:with-param name="text" select="$substring-after"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$substring-before"/>
<!--<xsl:text> </xsl:text>-->
<xsl:text>#</xsl:text>
<xsl:value-of select="$substring-after"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
The mode="widow-fix" can process both text nodes and paragraphs preserving the enclosing tag.
I used such document as a test source
<book>
<p>Highly random content</p>
in this book
</book>
which converts to the following
<book>
<p>Highly random#content</p>
in this#book
</book>