问题
I want to force a line break after a string length of 14 characters in a PDF generated with AH Formatter. So this is my xsl code without any attempt of line breaking:
<xsl:attribute-set name="big" use-attribute-sets="bold">
<xsl:attribute name="font-size">38pt</xsl:attribute>
<xsl:attribute name="line-height">28.84pt</xsl:attribute>
<xsl:attribute name="text-align">center</xsl:attribute>
<xsl:attribute name="letter-spacing">1mm</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="small" use-attribute-sets="bold">
<xsl:attribute name="font-size">27pt</xsl:attribute>
<xsl:attribute name="line-height">27pt</xsl:attribute>
<xsl:attribute name="text-align">center</xsl:attribute>
<xsl:attribute name="letter-spacing">1mm</xsl:attribute>
</xsl:attribute-set>
<xsl:choose>
<xsl:when test="string-length($count_cover)>=14">
<fo:block xsl:use-attribute-sets="small">
<xsl:apply-templates/>
</fo:block>
</xsl:when>
<xsl:otherwise>
<fo:block xsl:use-attribute-sets="big">
<xsl:apply-templates/>
</fo:block>
</xsl:otherwise>
</xsl:choose>
Is it possible to force a line break with XSL-FO?
回答1:
If the title can be converted into string, you can insert <fo:block/>
as line break.
<xsl:variable name="cover_title" as="xs:string" select="'Very Long Cover Title! Very Long Cover Title! Very Long Cover Title! '"/>
<xsl:variable name="count_cover" as="xs:integer" select="string-length($cover_title)"/>
<xsl:variable name="lf_position" as="xs:integer" select="14"/>
<xsl:template match="/">
<xsl:choose>
<xsl:when test="$count_cover gt $lf_position">
<fo:block xsl:use-attribute-sets="small">
<xsl:analyze-string select="$cover_title" regex=".{{1}}">
<xsl:matching-substring>
<xsl:value-of select="."/>
<xsl:if test="position() eq $lf_position">
<fo:block/>
</xsl:if>
</xsl:matching-substring>
<xsl:non-matching-substring/>
</xsl:analyze-string>
</fo:block>
</xsl:when>
<xsl:otherwise>
<fo:block xsl:use-attribute-sets="big">
<xsl:value-of select="$cover_title"/>
</fo:block>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
The result:
<fo:block font-weight="bold" font-size="27pt" line-height="27pt" text-align="center" letter-spacing="1mm">Very Long Cove<fo:block/>r Title! Very Long Cover Title! Very Long Cover Title! </fo:block>
However this method ignores word boundaries and hyphenation control. If you are intending to make book cover title, it will better to introduce AH Formatter extensions by using fo:block-container.
- Use fo:block-container for your title in fixed position and size in the cover page.
- Set property @overflow="condense" with @axf:overflow-condense=”font-size". https://www.antennahouse.com/product/ahf60/docs/ahf-ext.html#axf.overflow-condense
- Inside the fo:block-container, place fo:block that stores title contents.
- You can get desired result because AH Formatter automatically adjust the font-size according to the content volume.
[Example]
<fo:block-container position="absolute" top="..." left="..." width="..." height="..." overflow="condense" axf:overflow-condense="font-size" font-size="27pt" text-align="center">
<fo:block>
<fo:inline>Very Long Cover Title! Very Long Cover Title! Very Long Cover Title!</fo:inline>
</fo:block>
</fo:block-container>
回答2:
If you're trying to break words (rather than, e.g., part numbers), then enabling hyphenation may give you a better result than breaking after a fixed number of characters.
You can use
linefeed-treatment="preserve"
and insert

instead offo:block
, as this answer to Inserting a line break in a PDF generated from XSL FO using <xsl:value-of> notes. Which you can do with<xsl:value-of select="replace(., '(.{14})', '$1
')" />
You can instead insert a zero-width space,
​
, after every 14th character and let AH Formatter break on the zero-width space:<xsl:template match="text()"> <xsl:value-of select="replace(replace(., '(\P{Zs}{14})', '$1​'), '​(\p{Zs})', '$1')" /> </xsl:template>
The inner
replace()
inserts the character after every 14 non-space characters, and the outerreplace()
fixes it if the 15th character was a space character.If you're using a proportional-width font, some sequences of 14 characters (excluding, e.g., 14 constant-width lining numbers) will take more or less width than others, so you might want to insert
​
between more characters so that AH Formatter can do its best to fill the line before breaking.- You can use
axf:word-break="break-all"
to enable line breaking even inside a word. See https://www.antennahouse.com/product/ahf63/ahf-ext.html#axf.word-break
回答3:
You can't force a line break in FO, but you can split up the string into separate FO blocks.
<xsl:choose>
<xsl:when test="string-length($count_cover) >= 14">
<fo:block><xsl:value-of select="substring($count_cover, 1, 13)"/></fo:block>
<fo:block><xsl:value-of select="substring($count_cover, 14)"/></fo:block>
</when>
<xsl:otherwise>
<fo:block>
<xsl:value-of select="$count_cover"/>
</fo:block>
</xsl:otherwise>
</xsl:choose>
来源:https://stackoverflow.com/questions/36810691/force-line-break-after-string-length