Вставка разрыва строки в PDF, созданный с помощью XSL FO, с использованием <xsl: value-of>

Я использую 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 и т.д. Безрезультатно. Любые советы или помощь будут высоко оценены. Спасибо!

Ответы

Ответ 1

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

Ответ 2

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

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

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

Edit

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

Ответ 3

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

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

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

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

Ответ 4

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

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

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

Ответ 5

Попробуйте следующее:

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

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

Ответ 6

Создание строк, содержащих экранированную разметку 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>

Ответ 7

Для XSLT 1.0 я использую XSLT Line-Break Template на GitHub.

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

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

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

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

Ответ 8

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

<fo:block linefeed-treatment="preserve" >
 <xsl:value-of select="Description" />
</fo:block>

Ответ 9

</fo:block> сам по себе не является прямой заменой <br/> <br/> является html непарной аберрации, которая не имеет прямого эквивалента в xsl: fo

</fo:block> просто означает конец блока. Если вы разбросаете их по тексту, у вас не будет действительного xml, и ваш процессор xsl будет болеть за ошибки.

Для форматирования разрыва строки, который вы хотите, каждый блок будет появляться на новой строке. Для каждой строки вам нужен стартовый блок <fo:block> и пара торцевых блоков </fo:block>.