使用 <xsl:value-of> 在从 XSL FO 生成的 PDF 中插入换行符

Posted

技术标签:

【中文标题】使用 <xsl:value-of> 在从 XSL FO 生成的 PDF 中插入换行符【英文标题】:Inserting a line break in a PDF generated from XSL FO using <xsl:value-of> 【发布时间】:2011-04-09 08:32:51 【问题描述】:

我正在使用 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 中使用另一个 &lt;fo:block&gt; 元素中的 &lt;fo:block&gt;&lt;/fo:block&gt; 进行换行。因此,甚至在我用我的 XSL 样式表解析 XML 之前,我将所有出现的 &lt;br/&gt; 替换为 &lt;fo:block/&gt;,因此字符串的文字值现在看起来像:

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

当我使用的Description字符串是使用&lt;xsl:value-of&gt;获取时出现问题,示例如下:

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

在这种情况下,输出到我的 PDF 文档的值是文字值,因此它看起来与前面的示例完全相同,其中包含所有 &lt;fo:block/&gt; 文字。我尝试在另一个字符串中间手动硬编码&lt;fo:block/&gt;,它显示正确。例如。如果我在样式表中写:

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

它会正确显示为:

Te
st

但是当&lt;fo:block/&gt;&lt;xsl:value-of select=""/&gt; 语句的值内时,这似乎不会发生。我试过在 SO 和 Google 等上搜索这个,但无济于事。任何建议或帮助将不胜感激。谢谢!

【问题讨论】:

【参考方案1】:

您不应该使用xsl:value-of 指令,而是使用xsl:apply-templates:对于文本节点的内置规则只会输出它们的字符串值,对于空的br 元素,您可以声明匹配descriptionStr/br 的规则或descriptionStr//br(取决于您的输入)以转换为空 fo:block

【讨论】:

嗨亚历杭德罗,我想我明白你的意思......但就我而言,我很抱歉在我最初的问题中没有说清楚,我实际处理的字符串不是来自 XML 文件本身。它来自我使用 EXSLT str:split 函数 (exslt.org/str/functions/split/str.split.html) 构建的节点集。因此,节点集中的每个子节点都包含在“”元素标记中,因此我无法将模板与包含我的字符串的元素名称匹配。你认为我需要改变我的实现,以便我可以使用 apply-templates 调用吗?非常感谢。 @user311811:如果你有&lt;token&gt;This is an example Description.&lt;br/&gt;List item 1&lt;/token&gt;,你可以匹配token/br。但从你的问题来看,这个xsl:value-of select="descriptionStr" 表示descriptionStr 子元素的字符串值。 @user311811:您应该能够使用exslt:node-set() 将来自str:split() 的结果视为一个节点集。如果您能够使用 XSLT 2.0,这会容易得多。【参考方案2】:

您还可以将&lt;br/&gt; 替换为&amp;#xA;,并将linefeed-treatment="preserve" 属性添加到您的&lt;fo:block&gt;

类似:

<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 而不是&amp;#xA;,具体取决于他们创建 XML 的方式。详情请见Retain the &#xA; during xml marshalling。

【讨论】:

我正在尝试同样的事情,但无法正常工作。当我通过 xsd 生成 xml 时,我的输出是 &lt;description&gt;REPAIR CAB DOOR&amp;amp;#xA;REPAIR &amp;amp;#xA;&lt;/description&gt; 从而防止在我的 pdf 文档中添加换行符。你有什么想法 @user525146 - 当您说您通过 xsd 生成 xml(xsd 是一种模式)时,我不确定您的意思。您能否创建一个新问题,提供有关如何运行 XSL-FO 的示例和更多详细信息?如果您将问题的链接放在此处的评论中,我会尝试为您查找。 给你***.com/questions/13731652/…【参考方案3】:

&lt;/fo:block&gt; 本身不能直接替代 &lt;br/&gt; &lt;br/&gt; 是 html 未配对缩写,在 xsl:fo 中没有直接等效项

&lt;/fo:block&gt; 仅表示块结束。如果您将它们分散在您的文本中,您将没有有效的 xml,并且您的 xsl 处理器会出现错误。

对于您想要的换行格式,每个块将出现在新行上。每行都需要一个&lt;fo:block&gt; 起始块和&lt;/fo:block&gt; 结束块对。

【讨论】:

在 OP 或任何答案中提到它在哪里只是 &lt;/fo:block&gt; 正在使用或应该使用?【参考方案4】:

试试这个:

&lt;fo:block&gt;&lt;fo:inline color="transparent"&gt;x&lt;/fo:inline&gt;&lt;/fo:block&gt;

此代码添加了一个包含透明文本的块,使其看起来像一个新行。

【讨论】:

我不建议破解,而是建议一个答案。这显然是一个 hack。请参阅@Daniel Haley 以获得正确答案 我没有意识到这里有禁止黑客攻击的规则。【参考方案5】:

以下代码有效:

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

它使 xsl 处理器认为该块包含一行文本,实际上它的字体大小为 0pt。 您可以通过提供自己的值来自定义行高。

【讨论】:

【参考方案6】:

这对我有帮助,应该是最简单的解决方案(使用 Apache FOP 1.1):

为什么不用称为 行分隔符的 Unicode 字符替换您的 &lt;br/&gt;

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

见https://en.wikipedia.org/wiki/Newline#Unicode

【讨论】:

仅使用 &amp;#x2028; 对我有用,这是迄今为止最简单的方法,并且不会干扰为提高可读性而插入的换行符。【参考方案7】:

对于 XSLT 1.0,我在 GitHub 上使用我的 XSLT Line-Break Template。

对于 XSL-FO 它支持

换行符 换行符(与换行符相比) 连续的指针系列 忽略指针重复(禁用连续指针系列) 任何字符串作为指针插入分隔符或分隔符(默认为“\n”) 行分隔符的高度 当前字体大小的默认行分隔符高度。 在搜索中断位置时自动忽略“\r”字符。 添加了对 XSLT 2.0 的支持以实现无缝迁移。 别的...

对于 XSLT 2.0 及更高版本,请考虑使用类似的方法

XSLT 2.0 xsl:analyze-string (RegEx) XPath 2.0 标记化 + XSLT (RegEx) 将序列作为模板参数传递 (XSLT 2.0) 等等

【讨论】:

【参考方案8】:

尝试使用 linefeed-treatment="preserve" 和 \n 而不是 &lt;br&gt; 换行。

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

【讨论】:

【参考方案9】:

生成包含转义 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,您可以更简洁地使用 @Daniel Haley 的 linefeed-treatment="preserve" 并使用 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>

【讨论】:

【参考方案10】:

如果我需要更多或更少的空间,我通常会使用一个高度可以更改的空块:

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

我知道这不是最好看的解决方案,但它很实用。

【讨论】:

【参考方案11】:

我有一个像这样的文本块

<fo:table-cell display-align="right">
<fo:block font-size="40pt" text-align="right">
    <xsl:text> Text 1 </xsl:text>
    <fo:block> </fo:block>
    <xsl:text> Text2 </xsl:text>
    <fo:block> </fo:block>
    <xsl:text> Text 3</xsl:text>
</fo:block>

注意:注意空

【讨论】:

以上是关于使用 <xsl:value-of> 在从 XSL FO 生成的 PDF 中插入换行符的主要内容,如果未能解决你的问题,请参考以下文章

XsltListViewWebPart 中的 Javascript 代码给出解析错误

带有文本输出的 XSLT 空白控件

XSLT / XPath函数month-from-dateTime(datetime)未按预期工作

愚蠢且可能很简单的 XSL 问题

有没有一种简单的方法来表示 xsl 样式表中的引号?

只有 name 属性的 xsl:template 和 xsl:function 有啥区别