Вставка разрыва строки в 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/>
на 

и добавить к <fo:block>
атрибут linefeed-treatment="preserve"
.
Что-то вроде:
<fo:block linefeed-treatment="preserve">This is an example Description.
List item 1
List item 2
List item 3
List item 4</fo:block>
Edit
Некоторым пользователям может потребоваться использовать \n
вместо 

в зависимости от того, как они создают XML. См. Сохранить & #xA; во время xml marshalling для более подробной информации.
Ответ 3
Это помогло мне и должно быть самым простым решением (работа с Apache FOP 1.1):
Почему бы не заменить ваш <br/>
на символ Unicode, называемый разделителем строк.
<xsl:template match="br">
<xsl:value-of select="'
'"/>
</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="<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(., '<br/>', '
')" />
</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, '<br/>'))">
<xsl:value-of select="$text" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring-before($text, '<br/>')"/>
<xsl:text>
</xsl:text> <!-- or <fo:block /> -->
<xsl:call-template name="replace-br">
<xsl:with-param name="text" select="substring-after($text, '<br/>')"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Ответ 7
Для 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>
.