Oracle APEX中XSL-FO表格单元格长文本换行失效问题排查
首先,我得先拆解你遇到的两个核心问题:模板未生效(连红色文本验证都没反应)和长单词无法换行,再针对性给出解决方案。
一、先解决模板不生效的问题(红色文本没出现)
你写的全局text()模板大概率没被触发——因为在XSLT中,如果XML里的文本嵌套在更具体的节点(比如表格单元格的子节点),或者有其他优先级更高的模板匹配了文本节点,这个通用的text()模板就会被忽略。另外,你给call-template加color属性的方式是错误的,call-template只能通过with-param传参数,不能直接加属性。
修改方案:显式调用零宽空格模板
不要依赖全局的text()匹配,而是在处理表格单元格内容时,主动调用intersperse-with-zero-spaces模板,同时把红色样式加到输出里:
<!-- 假设你原来的单元格输出代码是这样的,修改成主动调用模板 --> <fo:table-cell xsl:use-attribute-sets="cell"> <fo:block> <xsl:call-template name="intersperse-with-zero-spaces"> <xsl:with-param name="str" select="."/> </xsl:call-template> </fo:block> </fo:table-cell>
然后修改intersperse-with-zero-spaces模板,把文本用红色的fo:inline包裹,方便验证:
<xsl:template name="intersperse-with-zero-spaces"> <xsl:param name="str"/> <xsl:variable name="spacechars"> 	
             ​ </xsl:variable> <!-- 用fo:inline设置红色,验证模板是否生效 --> <fo:inline color="red"> <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"> <xsl:with-param name="str" select="substring($str, 2)"/> </xsl:call-template> </xsl:if> </fo:inline> </xsl:template>
这样如果模板生效,单元格文本会变成红色,你就能确认模板是否被正确调用了。
二、解决长单词换行问题
除了零宽空格,还要确保XSL-FO的单元格和表格配置正确,以下是关键配置:
1. 修复单元格属性集的冲突和缺失
你的cell属性集里重复设置了color(先设#BODY_FONT_COLOR#又设blue),而且缺少连字的关键配置。修改后的属性集:
<xsl:attribute-set name="cell"> <xsl:attribute name="background-color">#BODY_BG_COLOR#</xsl:attribute> <xsl:attribute name="color">#BODY_FONT_COLOR#</xsl:attribute> <xsl:attribute name="padding-start">5.15pt</xsl:attribute> <xsl:attribute name="vertical-align">top</xsl:attribute> <xsl:attribute name="padding-top">0.0pt</xsl:attribute> <xsl:attribute name="padding-end">5.15pt</xsl:attribute> <xsl:attribute name="number-columns-spanned">1</xsl:attribute> <xsl:attribute name="height">0.0pt</xsl:attribute> <xsl:attribute name="padding-bottom">0.0pt</xsl:attribute> <xsl:attribute name="font-style">italic</xsl:attribute> <!-- 连字相关配置(英文内容生效) --> <xsl:attribute name="hyphenate">true</xsl:attribute> <xsl:attribute name="hyphenation-character">-</xsl:attribute> <xsl:attribute name="hyphenation-push-character-count">2</xsl:attribute> <!-- 连字前至少保留2个字符 --> <xsl:attribute name="hyphenation-remain-character-count">2</xsl:attribute> <!-- 连字后至少保留2个字符 --> <xsl:attribute name="wrap-option">wrap</xsl:attribute> <!-- 指定语言,让FO处理器知道用哪种连字规则 --> <xsl:attribute name="language">en</xsl:attribute> </xsl:attribute-set>
2. 必须给表格列设置明确宽度
如果表格列宽是auto,FO处理器会优先适应内容宽度,不会强制换行。你需要给列设置固定宽度或比例宽度:
<!-- 示例:设置固定宽度 --> <fo:table-column column-width="200pt"/> <fo:table-column column-width="150pt"/> <!-- 或者用比例宽度 --> <fo:table-column proportional-column-width="1"/> <fo:table-column proportional-column-width="2"/>
3. 终极替代方案:Apache FOP扩展属性
如果零宽空格和连字都无效,你可以用Apache FOP的扩展属性fox:word-break="break-all",强制长单词在任意字符处换行:
确保你的stylesheet已经声明了fox命名空间(你已经加了):
xmlns:fox="http://xml.apache.org/fop/extensions"
然后在cell属性集里添加:
<xsl:attribute name="fox:word-break">break-all</xsl:attribute>
关于intersperse-with-zero-spaces模板位置的问题
你的模板位置是正确的——在DOCUMENT模板之前定义,这样在处理DOCUMENT节点内的内容时可以正常调用。问题出在全局text()模板的匹配优先级,改成显式调用后就能解决。
内容的提问来源于stack exchange,提问作者Discipulus

