Apache FOP生成PDF时RTE富文本内容自动换行问题求助
Apache FOP生成PDF表格时RTE富文本换行异常问题
问题描述
应用使用Apache FOP生成PDF表格,长字符串超出列宽会出现溢出重叠的情况。目前两类UI数据表现不同:
- 文本框数据:已通过现有XSLT方案实现自动换行,显示正常
- RTE(富文本编辑器)数据:沿用文本框的换行方案时,出现重复打印、内容不显示或样式失效的问题,根源是RTE数据携带
<p>、<span>、<strong>、<u>等HTML标签,原代码无法识别标签结构,直接对整串文本做字符处理导致混乱。
以下是当前用于纯文本换行的XSLT代码(对带HTML标签的数据无效):
<xsl:template name="intersperse-with-zero-spaces"> <xsl:param name="str"/> <xsl:param name="column-width"/> <xsl:if test="string-length($str) > 0"> <xsl:variable name="s1" select="substring-before($str, ' ')"/> <xsl:variable name="s2" select="substring-after($str, ' ')"/> <xsl:variable name="chars-per-inch" select="number($column-width*6)" /> <xsl:if test="$s1 != '' and string-length($s1) < $chars-per-inch"> <xsl:value-of select="$s1" /> </xsl:if> <xsl:if test="$s1 != '' and string-length($s1) >= $chars-per-inch"> <xsl:call-template name="intersperse-with-zero-spaces-str"> <xsl:with-param name="str" select="$s1"/> </xsl:call-template> </xsl:if> <!-- Adding space after every word --> <xsl:text> </xsl:text> <xsl:call-template name="intersperse-with-zero-spaces"> <xsl:with-param name="str" select="$s2"/> <xsl:with-param name="column-width" select="$column-width"/> </xsl:call-template> </xsl:if> </xsl:template> <xsl:template name="intersperse-with-zero-spaces-str"> <xsl:param name="str"/> <xsl:variable name="spacechars">	
           ​</xsl:variable> <xsl:if test="string-length($str) > 0"> <xsl:variable name="c1" select="substring($str, 1, 1)" /> <xsl:variable name="c2" select="substring($str, 2, 1)" /> <xsl:value-of select="$c1"/> <xsl:if test="$c2 != '' and not(contains($spacechars, $c1) or contains($spacechars, $c2))"> <xsl:text>​</xsl:text> </xsl:if> <xsl:call-template name="intersperse-with-zero-spaces-str"> <xsl:with-param name="str" select="substring($str, 2)"/> </xsl:call-template> </xsl:if> </xsl:template>
解决方案
方案1:解析HTML标签并转换为FO格式(推荐,保留样式)
核心思路是先将RTE的HTML标签转换为Apache FOP支持的XSL-FO元素,再对纯文本节点应用换行逻辑,既保留富文本样式,又解决换行问题。
添加HTML到FO的转换模板
针对常用的RTE输出标签编写转换规则:<!-- 处理<p>段落标签,转为FO块级元素,自带段落间距 --> <xsl:template match="p"> <fo:block margin-bottom="6pt" wrap-option="wrap"> <xsl:apply-templates/> </fo:block> </xsl:template> <!-- 处理<strong>加粗标签 --> <xsl:template match="strong"> <fo:inline font-weight="bold"> <xsl:apply-templates/> </fo:inline> </xsl:template> <!-- 处理<u>下划线标签 --> <xsl:template match="u"> <fo:inline text-decoration="underline"> <xsl:apply-templates/> </fo:inline> </xsl:template> <!-- 处理<span>行内标签 --> <xsl:template match="span"> <fo:inline> <xsl:apply-templates/> </fo:inline> </xsl:template> <!-- 对文本节点应用原有的换行逻辑 --> <xsl:template match="text()"> <xsl:call-template name="intersperse-with-zero-spaces"> <xsl:with-param name="str" select="."/> <xsl:with-param name="column-width" select="$your-column-width"/> <!-- 替换为实际列宽参数 --> </xsl:call-template> </xsl:template>调用方式
将RTE的HTML内容当作XML节点处理(需确保HTML格式良好,标签闭合),通过apply-templates解析标签并应用样式和换行:<!-- 假设RTE数据存储在rte-content节点中 --> <fo:block wrap-option="wrap"> <xsl:apply-templates select="rte-content/node()"/> </fo:block>
方案2:移除HTML标签后处理(丢失样式,仅备选)
如果不需要保留富文本样式,可以先剥离所有HTML标签,再用原换行模板处理纯文本:
<xsl:template name="strip-html"> <xsl:param name="html"/> <xsl:choose> <xsl:when test="contains($html, '<')"> <xsl:value-of select="substring-before($html, '<')"/> <xsl:call-template name="strip-html"> <xsl:with-param name="html" select="substring-after($html, '>')"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$html"/> </xsl:otherwise> </xsl:choose> </xsl:template>
调用示例:
<xsl:variable name="clean-rte-text"> <xsl:call-template name="strip-html"> <xsl:with-param name="html" select="$rte-data"/> <!-- 替换为你的RTE数据变量 --> </xsl:call-template> </xsl:variable> <xsl:call-template name="intersperse-with-zero-spaces"> <xsl:with-param name="str" select="$clean-rte-text"/> <xsl:with-param name="column-width" select="$your-column-width"/> </xsl:call-template>
注意事项
- 确保RTE输出的HTML是格式良好的XML,所有标签闭合、特殊字符转义,否则XSLT无法正确解析。若HTML不规范,可先用JTidy等工具预处理。
- 在FO块中设置
wrap-option="wrap",确保Apache FOP启用自动换行逻辑。
内容的提问来源于stack exchange,提问作者Kartheek Gajavelly
相关产品推荐
相关产品推荐

