You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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) &gt; 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) &lt; $chars-per-inch">
            <xsl:value-of select="$s1" />
        </xsl:if>
        <xsl:if test="$s1 != '' and string-length($s1) &gt;= $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">&#x9;&#xA;&#x2000;&#x2001;&#x2002;&#x2003;&#x2004;&#x2005;&#x2006;&#x2007;&#x2008;&#x2009;&#x200A;&#x200B;</xsl:variable>
    <xsl:if test="string-length($str) &gt; 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>&#x200B;</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元素,再对纯文本节点应用换行逻辑,既保留富文本样式,又解决换行问题。

  1. 添加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>
    
  2. 调用方式
    将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, '&lt;')">
            <xsl:value-of select="substring-before($html, '&lt;')"/>
            <xsl:call-template name="strip-html">
                <xsl:with-param name="html" select="substring-after($html, '&gt;')"/>
            </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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 11:39:51