如何用XSLT 3.0压缩外部HTML文档输出的空白?
问题概述
用Apache FOP 2.8搭配支持XSLT 3.0的SaxonHE 12处理器,现有XSLT模板能把外部HTML的body内容嵌入输出,但输出存在大量冗余空白。尝试用normalize-space()处理document()获取的节点时,仅得到文本内容的拼接,无法生成保留HTML结构的压缩输出。
原XSLT模板:
<xsl:stylesheet version="1.0" xmlns:fopi="http://xmlgraphics.apache.org/fop/intermediate" xmlns:nav="http://xmlgraphics.apache.org/fop/intermediate/document-navigation" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:html="http://www.w3.org/TR/REC-html40"> <xsl:output method="html" version="4.0" encoding="utf-8" indent="no"/> <xsl:template name="embed-html"> <xsl:param name="path"/> <xsl:copy-of select="document($path)/html:html/html:body/*"/> </xsl:template> </xsl:stylesheet>
外部HTML示例(含冗余空白):
<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40"> <head> <style> </style> </head> <body> <table> <tr> <th>Company</th> <th>Contact</th> <th>Country</th> </tr> <tr> <td>Alfreds Futterkiste</td> <td>Maria Anders</td> <td>Germany</td> </tr> <tr> <td height="24" class="x64" width="115" style="height: 18pt; width: 86.25pt"> <a><span style="font-size: 7pt; color: #000000;"/> </a> </td> <td>Francisco Chang</td> <td>Mexico</td> </tr> </table> </body> </html>
之前尝试的错误写法(仅生成文本拼接):
<xsl:template name="embed-html"> <xsl:param name="path"/> <xsl:copy-of select="normalize-space(document($path)/html/body/*)"/> </xsl:template>
解决方案
问题出在normalize-space()直接作用于节点集时,会提取所有节点的文本内容并拼接成纯字符串,完全丢失HTML结构。要保留结构同时压缩空白,需要通过XSLT模板匹配处理节点树,过滤冗余空白文本节点,同时规范化必要的文本内容。
修改后的XSLT代码(基于XSLT 3.0特性):
<xsl:stylesheet version="3.0" xmlns:fopi="http://xmlgraphics.apache.org/fop/intermediate" xmlns:nav="http://xmlgraphics.apache.org/fop/intermediate/document-navigation" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:html="http://www.w3.org/TR/REC-html40"> <xsl:output method="html" version="4.0" encoding="utf-8" indent="no"/> <!-- 通用模板:复制元素及属性,递归处理子节点 --> <xsl:template match="*"> <xsl:copy> <xsl:copy-of select="@*"/> <xsl:apply-templates/> </xsl:copy> </xsl:template> <!-- 过滤纯空白文本节点,对非空白文本做空格规范化 --> <xsl:template match="text()"> <xsl:variable name="trimmed" select="normalize-space(.)"/> <xsl:if test="$trimmed != ''"> <xsl:value-of select="$trimmed"/> </xsl:if> </xsl:template> <!-- 修改后的嵌入模板:用apply-templates触发空白处理逻辑 --> <xsl:template name="embed-html"> <xsl:param name="path"/> <xsl:apply-templates select="document($path)/html:html/html:body/*"/> </xsl:template> </xsl:stylesheet>
关键说明
- 将XSLT版本改为
3.0,充分利用SaxonHE 12的原生支持; - 新增元素模板:复制所有元素及其属性,递归处理子节点以保留完整HTML结构;
- 文本节点模板:过滤完全空白的文本节点,对有实际内容的文本做
normalize-space(),去除首尾空白并合并中间连续空格; - 嵌入模板改用
xsl:apply-templates,让外部HTML的每个节点都经过空白处理逻辑,最终输出保留结构且无冗余空白的压缩HTML。
内容的提问来源于stack exchange,提问作者CrazyEight
相关产品推荐
相关产品推荐

