Принудительный разрыв строки после длины строки

Я хочу заставить разрыв строки после длины строки 14 символов в PDF, сгенерированном с помощью AH Formatter. Так что это мой xsl-код без каких-либо попыток разрыва строки:

<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>

Можно ли форсировать разрыв строки с помощью XSL-FO?

3 ответа

Решение

Если заголовок может быть преобразован в строку, вы можете вставить <fo:block/> как разрыв строки.

<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>

Результат:

<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>

Однако этот метод игнорирует границы слов и управление переносами. Если вы собираетесь сделать заголовок обложки книги, лучше ввести расширения AH Formatter, используя fo:block-container.

  1. Используйте fo: block-container для вашего заголовка в фиксированном положении и размере на титульной странице.
  2. Установите свойство @overflow="конденсировать" с помощью @axf:overflow-conse= "font-size". https://www.antennahouse.com/product/ahf60/docs/ahf-ext.html
  3. Внутри fo: block-container поместите fo: block, в котором хранится содержимое заголовка.
  4. Вы можете получить желаемый результат, потому что AH Formatter автоматически регулирует размер шрифта в соответствии с объемом содержимого.

[Пример]

<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>
  1. Если вы пытаетесь разбить слова (а не, например, номера деталей), то включение переноса может дать вам лучший результат, чем разбивание после фиксированного числа символов.

  2. Ты можешь использовать linefeed-treatment="preserve" и вставить &#xA; вместо fo:block, как этот ответ на Вставку разрыва строки в PDF, сгенерированном из XSL FO с использованием заметок ;. Что вы можете сделать с <xsl:value-of select="replace(., '(.{14})', '$1&#xA;')" />

  3. Вместо этого вы можете вставить пробел нулевой ширины, &#x200B;, после каждого 14-го символа и пусть AH Formatter разбивается на пробел нулевой ширины:

    <xsl:template match="text()"> <xsl:value-of select="replace(replace(., '(\P{Zs}{14})', '$1&#x200B;'), '&#x200B;(\p{Zs})', '$1')" /> </xsl:template>

    Внутренний replace() вставляет символ после каждых 14 непробельных символов, а внешний replace() исправляет это, если 15-й символ был пробелом.

    Если вы используете шрифт пропорциональной ширины, некоторые последовательности из 14 символов (исключая, например, 14 чисел с постоянной шириной) будут иметь большую или меньшую ширину, чем другие, поэтому вы можете захотеть вставить &#x200B; между несколькими символами, так что AH Formatter может сделать все возможное, чтобы заполнить строку перед разрывом.

  4. Ты можешь использовать axf:word-break="break-all" включить разрыв строки даже внутри слова. См. https://www.antennahouse.com/product/ahf63/ahf-ext.html.

Вы не можете форсировать разрыв строки в FO, но вы можете разбить строку на отдельные блоки FO.

<xsl:choose>
  <xsl:when test="string-length($count_cover) &gt;= 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>
Другие вопросы по тегам