如何用XSLT 1.0将XML中CRLF转为LF适配Excel单元格换行
解决XSLT 1.0替换CR为Excel可识别的LF实体问题
问题原因
你遇到的核心问题是:
- 源XML中的
会被XSLT解析器转换成实际的CR(回车,ASCII 13)字符,而非保留字面量的 字符串。 - 直接用
translate(comment,' ',' ')只是将CR字符替换为LF(换行,ASCII 10)字符,但默认XSLT输出时不会将LF转义为 实体;而Excel的XML表格格式需要显式的 实体才能识别单元格内换行,实际的LF字符无法被正确解析。 - 开启
disable-output-escaping的方向没错,但之前的用法没有针对实体输出做处理。
解决方案
方法1:递归模板替换CR为 实体(推荐)
由于XSLT 1.0没有原生的字符串替换函数,我们可以用递归模板逐个将CR字符替换为 实体:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 匹配根节点,复制所有其他节点 --> <xsl:template match="/|*"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 匹配需要处理的comment节点 --> <xsl:template match="comment"> <xsl:copy> <xsl:call-template name="replace-cr-with-lf-entity"/> </xsl:copy> </xsl:template> <!-- 递归替换CR为 实体的模板 --> <xsl:template name="replace-cr-with-lf-entity"> <xsl:param name="text" select="."/> <xsl:choose> <xsl:when test="contains($text, '
')"> <!-- 输出CR之前的内容 --> <xsl:value-of select="substring-before($text, '
')"/> <!-- 输出 实体,disable-output-escaping确保&不被转义 --> <xsl:text disable-output-escaping="yes">&#10;</xsl:text> <!-- 递归处理剩余内容 --> <xsl:call-template name="replace-cr-with-lf-entity"> <xsl:with-param name="text" select="substring-after($text, '
')"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$text"/> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet>
方法2:字符替换后强制转义LF为
如果你只想用translate,可以先将CR替换为LF,再通过输出实体的方式生成 :
<xsl:template match="comment"> <xsl:copy> <xsl:variable name="lf-text" select="translate(., '
', '
')"/> <xsl:for-each select="string-to-codepoints($lf-text)"> <xsl:choose> <xsl:when test=". = 10"> <xsl:text disable-output-escaping="yes">&#10;</xsl:text> </xsl:when> <xsl:otherwise> <xsl:value-of select="codepoints-to-string(.)"/> </xsl:otherwise> </xsl:choose> </xsl:for-each> </xsl:copy> </xsl:template>
注意事项
- 确保Notepad++的XML Tools插件使用的XSLT处理器支持
disable-output-escaping(libxslt是支持的)。 - 转换后打开Excel时,要确保对应单元格的自动换行功能已开启。
内容的提问来源于stack exchange,提问作者Nick Lines
相关产品推荐
相关产品推荐

