Search code examples
xsltxsl-fo

XSL word wrapping issue


I have a table coded in XSL which is used to generate a pdf when executed. There is an issue when a user enters data into the CountryGroup table cell. If there are no spaces in the data it will break the boundaries of the cell and the data will spill into other cells making the document unreadable.

I am trying to figure out a way to make the text wrap. Please see the code snippet below:

 <fo:table-cell border="1pt solid black" display-align="after"><fo:block>Customer Seq Range</fo:block></fo:table-cell>
           <fo:table-cell border="1pt solid black" display-align="after"><fo:block>Label Code</fo:block></fo:table-cell>
           <fo:table-cell border="1pt solid black" display-align="after"><fo:block>Labelled Lot</fo:block></fo:table-cell>
           <fo:table-cell border="1pt solid black" display-align="after"><fo:block>Country Group</fo:block></fo:table-cell> <!--NCCRC200003  Country Group -->
           <fo:table-cell border="1pt solid black" display-align="after"><fo:block>Lot Expiry</fo:block></fo:table-cell>
           <fo:table-cell border="1pt solid black" display-align="after"><fo:block>QTY</fo:block></fo:table-cell>
     </fo:table-row>
    </fo:table-header>
    <fo:table-body>
    <fo:table-row font-size="9pt" font-weight="normal">
        <fo:table-cell border="1pt solid black" padding="3mm 0mm" display-align="center"><fo:block><xsl:value-of select="ItemNumber"/></fo:block></fo:table-cell>
        <fo:table-cell border="1pt solid black" padding="3mm 0mm" display-align="center"><fo:block><xsl:value-of select="RangeStart"/>-<xsl:value-of select="RangeEnd"/></fo:block></fo:table-cell>
        <fo:table-cell border="1pt solid black" padding="3mm 0mm" display-align="center"><fo:block><xsl:value-of select="CustRangeStart"/>-<xsl:value-of select="CustRangeEnd"/></fo:block></fo:table-cell>
        <fo:table-cell border="1pt solid black" padding="3mm 0mm" display-align="center"><fo:block><xsl:value-of select="LabelType"/></fo:block></fo:table-cell>
        <fo:table-cell border="1pt solid black" padding="3mm 0mm" display-align="center"><fo:block><xsl:value-of select="OtherLot"/></fo:block></fo:table-cell>
        <fo:table-cell border="1pt solid black" padding="3mm 0mm" display-align="center"><fo:block><xsl:value-of select="CountryGroup"/></fo:block></fo:table-cell> <!--NCCRC200003  Country Group. -->
        <fo:table-cell border="1pt solid black" padding="3mm 0mm" display-align="center"><fo:block><xsl:value-of select="ExpiryDate"/></fo:block></fo:table-cell>
        <fo:table-cell border="1pt solid black" padding="3mm 0mm" display-align="center"><fo:block><xsl:value-of select="Quantity"/></fo:block></fo:table-cell>
    </fo:table-row> 

Solution

  • If you want a block to wrap into several lines when no spaces are present in the text, try to define the attribute wrap-option to "wrap".

    If I reindent your code, you have:

    <fo:table-cell border="1pt solid black" padding="3mm 0mm" 
       display-align="center">
      <fo:block>
        <xsl:value-of select="CountryGroup"/>
      </fo:block>
    </fo:table-cell>
    

    I would change the code above by:

    <fo:table-cell border="1pt solid black" padding="3mm 0mm" 
       display-align="center">
      <fo:block wrap-option="wrap"><!-- added wrap-option attribute here -->
        <xsl:value-of select="CountryGroup"/>
      </fo:block>
    </fo:table-cell>
    

    More information about this here: XSL-FO fop. Long text flows into adjacent cells/block, obscuring stuff there

    If this doesn't work, you can inject zero-width spaces into your block, hoping this will help to wrap your text into several lines:

    <xsl:template name="string-replace-all">
      <xsl:param name="text" />
      <xsl:param name="replace" />
      <xsl:param name="by" />
      <xsl:choose>
        <xsl:when test="contains($text, $replace)">
          <xsl:value-of select="substring-before($text,$replace)" />
          <xsl:value-of select="$by" />
          <xsl:call-template name="string-replace-all">
            <xsl:with-param name="text"
            select="substring-after($text,$replace)" />
            <xsl:with-param name="replace" select="$replace" />
            <xsl:with-param name="by" select="$by" />
          </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$text" />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:template>
    

    This is a snippet of code I found here: XSLT 1.0: Replacing all occurences of a string in a node-set

    Instead of

        <xsl:value-of select="CountryGroup"/>
    

    You could try (edited according to suggestions below):

        <xsl:call-template name="string-replace-all">
          <xsl:with-param name="text" select="CountryGroup"/>
          <xsl:with-param name="replace" select="','"/>
          <xsl:with-param name="by" select="',&#8203;'"/>
        </xsl:call-template>
    

    For the zero width space, I used its Unicode &#8203;. If you work with another encoding, you will need to adjust this.