
本文详解如何在 XSLT(特别是 Saxon 12 HE + XSLT 1.0/3.0)中安全嵌入外部 HTML 并实现真正的“最小化输出”:既去除元素间冗余换行缩进,又规范化 style 等属性内的多余空格,避免 normalize-space() 直接作用于节点导致内容坍缩的常见错误。
本文详解如何在 xslt(特别是 saxon 12 he + xslt 1.0/3.0)中安全嵌入外部 html 并实现真正的“最小化输出”:既去除元素间冗余换行缩进,又规范化 `style` 等属性内的多余空格,避免 `normalize-space()` 直接作用于节点导致内容坍缩的常见错误。
在使用 XSLT 动态嵌入外部 HTML 片段(如通过 document($path))生成紧凑 HTML 输出时,开发者常遇到两类空白问题:
-
元素级空白:HTML 源文件中
和 之间的换行与缩进被原样复制,导致输出格式松散; - 属性值内空白:如 中的多空格、换行未被压缩,违反 CSS 属性语义且增大体积。
直接对节点集使用 normalize-space()(如 normalize-space(document(...)))是无效的——它会将整个子树文本内容拼接为单个字符串,丢失所有标签结构。正确方案需分层处理:结构去空 + 属性规范化。
✅ 正确做法:组合 xsl:strip-space 与专用模板模式
首先,全局声明
可移除 XML 解析阶段产生的“空白文本节点”(即元素间的纯空白),这对
内部的换行缩进生效:... <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:html="http://www.w3.org/TR/REC-html40"> <xsl:output method="html" version="4.0" encoding="utf-8" indent="no"/> <xsl:strip-space elements="*"/> <!-- 关键:剥离输入文档中元素间的空白文本节点 --> <!-- 主模板:嵌入外部 HTML body 内容 --> <xsl:template name="embed-html"> <xsl:param name="path"/> <!-- 推送节点至 'minify' 模式进行深度处理 --> <xsl:apply-templates select="document($path)/html:html/html:body/*" mode="minify"/> </xsl:template> <!-- minify 模式:递归复制所有节点,并规范化关键属性 --> <xsl:template match="node() | @*" mode="minify"> <xsl:copy> <xsl:apply-templates select="node() | @*" mode="minify"/> </xsl:copy> </xsl:template> <!-- 专门处理 style 属性:标准化其值(可扩展至 class、title 等) --> <xsl:template match="@style" mode="minify"> <xsl:attribute name="style" select="normalize-space(.)"/> </xsl:template> <!-- 可选:规范化其他易含空格的属性 --> <xsl:template match="@class | @title | @alt" mode="minify"> <xsl:attribute name="{name()}" select="normalize-space(.)"/> </xsl:template> </xsl:stylesheet>? 原理说明:
立即学习“前端免费学习笔记(深入)”;
-
在解析外部 HTML 文档时,丢弃所有仅由空白字符构成的文本节点(如 \n … 中的 \n),使 document($path)/.../* 选取的节点更“干净”; - mode="minify" 提供了安全的模板作用域,避免干扰主流程;
- @style 模板显式提取属性值 .,用 normalize-space() 压缩内部空格(如 "height: 18pt; width: 86.25pt" → "height: 18pt; width: 86.25pt"),再重建属性。
⚠️ 注意事项与边界说明
- XML 解析器已做基础规范化:根据 XML 规范 §3.3.3,XML 解析器会将属性值中的换行、制表符等统一转为空格,并折叠连续空格。因此,normalize-space() 主要解决的是“人为插入的多空格”问题,而非解析器未覆盖的场景。
-
不适用于 CDATA 或文本内容压缩:本方案聚焦于结构与属性精简。若需进一步压缩 HTML 文本节点(如去除
Hello
中的首尾空格),需额外添加 match="text()" 模板并谨慎处理(避免误删有意义空格)。 - 命名空间兼容性:示例中使用 html: 前缀匹配带命名空间的 HTML。若外部文档无默认命名空间(如测试用例2),请改用 match="*/@style" 或调整前缀绑定。
-
Saxon 12 HE 兼容性:上述 XSLT 1.0 写法完全兼容 Saxon HE 12。若升级至 XSLT 3.0,可利用 xsl:mode 声明简化模式定义:
<xsl:mode name="minify" on-no-match="shallow-copy"/> <xsl:template match="@style" mode="minify"> <xsl:attribute name="style" select="normalize-space(.)"/> </xsl:template>
✅ 验证效果
应用该样式表后,原始含缩进的 HTML 片段将输出为真正紧凑的单行格式(属性空格已压缩):
<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>
? 总结:XSLT 的空白控制是“分层工程”——xsl:strip-space 处理结构空白,专用模板处理属性空白,二者缺一不可。切勿尝试用 normalize-space() 直接包裹节点选择表达式,那只会摧毁 HTML 结构。掌握这一组合模式,即可在生成 PDF(如 Apache FOP)、静态站点或邮件模板时,精准交付轻量、规范的 HTML 输出。











