Вставка разрыва строки в PDF-файл, созданный из XSL FO с использованием <xsl: value-of> - PullRequest
21 голосов
/ 07 сентября 2010

Я использую XSL FO для создания файла PDF, содержащего таблицу с информацией. Один из этих столбцов является столбцом «Описание». Пример строки, которую я заполняю одним из этих полей описания, выглядит следующим образом:

This is an example Description.<br/>List item 1<br/>List item 2<br/>List item 3<br/>List item 4

Внутри ячейки таблицы, которая соответствует этому описанию, я бы хотел, чтобы вывод отображался следующим образом:

This is an example Description.
List item 1
List item 2
List item 3
List item 4

Я узнал из поиска в другом месте, что вы можете делать разрывы строк в XSL FO, используя <fo:block></fo:block> внутри другого <fo:block> элемента. Поэтому, даже прежде чем я проанализирую XML с моей таблицей стилей XSL, я заменяю все вхождения <br/> на <fo:block/>, так что буквальное значение строки теперь выглядит так:

This is an example Description.<fo:block/>List item 1<fo:block/>List item 2<fo:block/>List item 3<fo:block/>List item 4

Проблема возникает, когда строка описания, которую я использую, получается с использованием <xsl:value-of>, например, следующим образом:

<fo:block>
    <xsl:value-of select="descriptionStr"/>
</fo:block>

В этом случае значение, которое выводится в мой PDF-документ, является литеральным значением, поэтому оно выглядит точно так же, как и в предыдущем примере со всеми литералами <fo:block/>. Я попытался вручную жестко кодировать <fo:block/> в середине другой строки, и он отображается правильно. Например. если я напишу в моей таблице стилей:

<fo:block>Te<fo:block/>st</fo:block>

Будет отображаться правильно как:

Te
st

Но, похоже, этого не происходит, когда <fo:block/> находится внутри значения оператора <xsl:value-of select=""/>. Я пытался найти это на SO, а также в Google и т. Д. Безрезультатно. Любой совет или помощь будут с благодарностью. Спасибо!

Ответы [ 11 ]

39 голосов
/ 08 сентября 2010

Вы также можете заменить <br/> на &#xA; и добавить атрибут linefeed-treatment="preserve" к своему <fo:block>.

Что-то вроде:

<fo:block linefeed-treatment="preserve">This is an example Description.&#xA;List item 1&#xA;List item 2&#xA;List item 3&#xA;List item 4</fo:block>

Редактировать

Некоторым пользователям может понадобиться использовать \n вместо &#xA; в зависимости от того, как они создают XML.См. Сохраните во время XML-сортировки для получения более подробной информации.

8 голосов
/ 15 декабря 2015

Это помогло мне и должно быть самым простым решением (работа с Apache FOP 1.1):

Почему бы не заменить <br/> на символ Unicode, называемый разделитель строк .

   <xsl:template match="br">
      <xsl:value-of select="'&#x2028;'"/>
   </xsl:template>

См. https://en.wikipedia.org/wiki/Newline#Unicode

6 голосов
/ 30 августа 2013

Сработал следующий код:

<fo:block white-space-collapse="false" 
    white-space-treatment="preserve" 
    font-size="0pt" line-height="15px">.</fo:block>

Это заставляет процессор xsl думать, что этот блок содержит строку текста, которая на самом деле имеет размер шрифта 0pt. Вы можете настроить высоту строки, указав собственное значение.

5 голосов
/ 07 сентября 2010

Вы не должны использовать инструкцию xsl:value-of, но вместо этого xsl:apply-templates: для встроенного правила для текстового узла будет просто выводиться их строковое значение, а для пустого элемента br вы можете объявить правило, соответствующее descriptionStr/br илиdescriptionStr//br (в зависимости от вашего ввода) для преобразования в пустое значение fo:block.

2 голосов
/ 13 августа 2016

Создание строк, содержащих разметку с экранированием XML, редко является правильным ответом, но если это то, с чем вам придется работать, то для ввода, например, так:

<Description><![CDATA[This is an example Description.<br/>List item 1<br/>List item 2<br/>List item 3<br/>List item 4]]></Description>

если вы используете XSLT 2.0, вы можете использовать xsl:analyze-string, чтобы получить пустой fo:block, который вы изначально хотели:

<xsl:template match="Description">
  <fo:block>
    <xsl:analyze-string select="." regex="&lt;br/>">
      <xsl:matching-substring>
        <fo:block />
      </xsl:matching-substring>
      <xsl:non-matching-substring>
        <xsl:value-of select="." />
      </xsl:non-matching-substring>
    </xsl:analyze-string>
  </fo:block>
</xsl:template>

но если вы используете XSLT 2.0, вы можете более кратко использовать linefeed-treatment="preserve" согласно @Daniel Haley и использовать replace() для вставки перевода строки:

<xsl:template match="Description">
  <fo:block linefeed-treatment="preserve">
    <xsl:value-of select="replace(., '&lt;br/>', '&#xA;')" />
  </fo:block>
</xsl:template>

Если вы используете XSLT 1.0, вы можете повторить свой путь через строку:

<xsl:template match="Description">
  <fo:block linefeed-treatment="preserve">
    <xsl:call-template name="replace-br" />
  </fo:block>
</xsl:template>

<xsl:template name="replace-br">
  <xsl:param name="text" select="." />

  <xsl:choose>
    <xsl:when test="not(contains($text, '&lt;br/>'))">
      <xsl:value-of select="$text" />
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="substring-before($text, '&lt;br/>')"/>
      <xsl:text>&#xA;</xsl:text> <!-- or <fo:block /> -->
      <xsl:call-template name="replace-br">
        <xsl:with-param name="text" select="substring-after($text, '&lt;br/>')"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>
1 голос
/ 29 августа 2013

Попробуйте:

<fo:block><fo:inline color="transparent">x</fo:inline></fo:block>

Этот код добавляет блок, который содержит прозрачный текст, и выглядит как новая строка.

0 голосов
/ 20 февраля 2019

У меня был текстовый блок, который выглядит так

0 голосов
/ 27 декабря 2018

Я обычно использую пустой блок с высотой, которую можно изменить, если мне нужно больше или меньше места:

<fo:block padding-top="5mm" />

Я знаю, что это не лучшее решение, но оно функциональное.

0 голосов
/ 19 июля 2016

Попробуйте использовать linefeed-treatment = "preserve" и \ n вместо <br> для новой строки.

<fo:block linefeed-treatment="preserve" >
 <xsl:value-of select="Description" />
</fo:block>
0 голосов
/ 20 января 2016

Для XSLT 1.0 я использую мой XSLT-шаблон разрыва строки на GitHub.

Для XSL-FO поддерживается

  • Разрывы строк
  • Разделители строк (против разрывов строк)
  • Ряд указателей подряд
  • Игнорировать повторения указателей (отключить ряд указателей подряд)
  • Любая строка в качестве указателя для вставки разрыва или разделителя (по умолчанию "\ n")
  • Высота разделителей строк
  • Высота разделителя строки по умолчанию от текущего размера шрифта.
  • Автоматическое игнорирование символа "\ r" при поиске места останова.
  • Добавлена ​​поддержка XSLT 2.0 для плавной миграции.
  • что-то еще ...

Для XSLT 2.0 и более поздних версий рекомендуется использовать такие подходы, как

  • XSLT 2.0 xsl: анализ строки (RegEx)
  • токен XPath 2.0 + XSLT (RegEx)
  • передача последовательностей в качестве параметра шаблона (XSLT 2.0)
  • и т. Д.
...