XSLT 中嵌入外部 HTML 时的空白压缩与属性规范化实战指南

13次阅读

XSLT 中嵌入外部 HTML 时的空白压缩与属性规范化实战指南

本文详解如何在 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 输出。

text=ZqhQzanResources