使用 <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 中使用另一个 <fo:block>
元素中的 <fo:block></fo:block>
进行换行。因此,甚至在我用我的 XSL 样式表解析 XML 之前,我将所有出现的 <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
当我使用的Description字符串是使用<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
:对于文本节点的内置规则只会输出它们的字符串值,对于空的br
元素,您可以声明匹配descriptionStr/br
的规则或descriptionStr//br
(取决于您的输入)以转换为空 fo:block
。
【讨论】:
嗨亚历杭德罗,我想我明白你的意思......但就我而言,我很抱歉在我最初的问题中没有说清楚,我实际处理的字符串不是来自 XML 文件本身。它来自我使用 EXSLT str:split 函数 (exslt.org/str/functions/split/str.split.html) 构建的节点集。因此,节点集中的每个子节点都包含在“<token>This is an example Description.<br/>List item 1</token>
,你可以匹配token/br
。但从你的问题来看,这个xsl:value-of select="descriptionStr"
表示descriptionStr
子元素的字符串值。
@user311811:您应该能够使用exslt:node-set()
将来自str:split()
的结果视为一个节点集。如果您能够使用 XSLT 2.0,这会容易得多。【参考方案2】:
您还可以将<br/>
替换为&#xA;
,并将linefeed-treatment="preserve"
属性添加到您的<fo:block>
。
类似:
<fo:block linefeed-treatment="preserve">This is an example Description.
List item 1
List item 2
List item 3
List item 4</fo:block>
编辑
某些用户可能需要使用\n
而不是&#xA;
,具体取决于他们创建 XML 的方式。详情请见Retain the 
 during xml marshalling。
【讨论】:
我正在尝试同样的事情,但无法正常工作。当我通过 xsd 生成 xml 时,我的输出是<description>REPAIR CAB DOOR&amp;#xA;REPAIR &amp;#xA;</description>
从而防止在我的 pdf 文档中添加换行符。你有什么想法
@user525146 - 当您说您通过 xsd 生成 xml(xsd 是一种模式)时,我不确定您的意思。您能否创建一个新问题,提供有关如何运行 XSL-FO 的示例和更多详细信息?如果您将问题的链接放在此处的评论中,我会尝试为您查找。
给你***.com/questions/13731652/…【参考方案3】:
</fo:block>
本身不能直接替代 <br/>
<br/>
是 html 未配对缩写,在 xsl:fo 中没有直接等效项
</fo:block>
仅表示块结束。如果您将它们分散在您的文本中,您将没有有效的 xml,并且您的 xsl 处理器会出现错误。
对于您想要的换行格式,每个块将出现在新行上。每行都需要一个<fo:block>
起始块和</fo:block>
结束块对。
【讨论】:
在 OP 或任何答案中提到它在哪里只是</fo:block>
正在使用或应该使用?【参考方案4】:
试试这个:
<fo:block><fo:inline color="transparent">x</fo:inline></fo:block>
此代码添加了一个包含透明文本的块,使其看起来像一个新行。
【讨论】:
我不建议破解,而是建议一个答案。这显然是一个 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 字符替换您的 <br/>
。
<xsl:template match="br">
<xsl:value-of select="'
'"/>
</xsl:template>
见https://en.wikipedia.org/wiki/Newline#Unicode
【讨论】:
仅使用&#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 而不是 <br>
换行。
<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="<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(., '<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>
【讨论】:
【参考方案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 代码给出解析错误