White-space handling

Page Contents

在模板中控制white-space是一个问题,在某种程度上困扰着企业中的每个模板引擎。

让我们看看这个模板。我已经用颜色标记了模板的组件:文本,插值,FTL 标签。使用* [BR] * -s 可以看到line breaks

<p>List of users:[BR]
<#assign users = [{"name":"Joe",        "hidden":false},[BR]
                  {"name":"James Bond", "hidden":true},[BR]
                  {"name":"Julia",      "hidden":false}]>[BR]
<ul>[BR]
<#list users as user>[BR]
  <#if !user.hidden>[BR]
  <li>${user.name}[BR]
  </#if>[BR]
</#list>[BR]
</ul>[BR]
<p>That's all.

如果 FreeMarker 照原样输出所有文本,则输出为:

<p>List of users:[BR]
[BR]
<ul>[BR]
[BR]
  [BR]
  <li>Joe[BR]
  [BR]
[BR]
  [BR]
[BR]
  [BR]
  <li>Julia[BR]
  [BR]
[BR]
</ul>[BR]
<p>That's all.

您这里有很多多余的空格和换行符。幸运的是,HTML 和 XML 都不都是空白敏感的,但是这种多余的空白可能很烦人,并且不必要地增加了生成的 HTML 的大小。当然,在输出对空格敏感的格式时,这甚至是更大的问题。

FreeMarker 提供了以下工具来解决此问题:

  • 忽略模板文件中某些空白的工具(解析时间空白删除):

  • 空格剥离:此功能会自动忽略 FTL 标签周围的典型多余空格。可以按模板方式启用或禁用它。

    • 微调指令:trtlt。使用这些指令,您可以明确地告诉 FreeMarker 忽略某些空格。阅读the reference以获取更多信息。

    • ftl参数strip_text:这将从模板中删除所有顶级文本。这对于仅包含宏定义(以及一些其他非输出指令)的模板很有用,因为它消除了您在宏定义之间以及其他顶级指令之间使用的换行符,以提高模板的可读性。

  • 可以从输出中删除空格的工具(即时删除空格):

  • compress指令。

White-space stripping

如果为模板启用了此功能,则它将自动忽略(即不打印到输出)两种典型的多余空白:

  • 在仅包含 FTL 标签(例如<@myMacro/><#if ...>)和/或 FTLComments(例如<#-- blah -->)的行中,行尾的缩进空格和尾随空格(包括换行符)将被忽略。被忽略的空白本身。例如,如果一行仅包含<#if ...>,则标签之前的缩进和标签之后的换行符将被忽略。但是,如果该行包含<#if ...>x,那么由于x,该行中的空白将不会被忽略,因为这不是 FTL 标记。请注意,根据这些规则,包含<#if ...><#list ...>的行将被忽略空格,而包含<#if ...> <#list ...>的行则不会被忽略,因为两个 FTL 标签之间的空白是嵌入的空白,而不是缩进或尾随空白-空间。

  • 夹在以下指令之间的空白将被忽略:macrofunctionassigngloballocalftlimport,但前提是指令之间仅空格和/或 FTLComments。实际上,这意味着您可以在宏定义和分配之间放置空格作为间隔,以提高可读性,而无需在输出中打印不必要的空格(换行符)。

启用了空格剥离的最后一个示例的输出将是:

<p>List of users:[BR]
<ul>[BR]
  <li>Joe[BR]
  <li>Julia[BR]
</ul>[BR]
<p>That's all.

这是因为剥离后的模板如下所示;被忽略的文本未着色:

<p>List of users:[BR]
<#assign users = [{"name":"Joe",        "hidden":false},[BR]
                  {"name":"James Bond", "hidden":true},[BR]
                  {"name":"Julia",      "hidden":false}]>[BR]
<ul>[BR]
<#list users as user>[BR]
  <#if !user.hidden>[BR]
  <li>${user.name}[BR]
  </#if>[BR]
</#list>[BR]
</ul>[BR]
<p>That's all.

可以使用ftl directive以每种模板方式启用/禁用空格剥离。如果您未使用ftl指令指定此选项,则将根据程序员配置 FreeMarker 的方式来启用或禁用空格剥离。出厂默认设置为启用空白剥离,并且程序员可能将其保留为空白(建议)。请注意,启用空格剥离不会不会降低模板执行的性能;在模板加载过程中完成了空格剥离。

可以使用nt指令为单行禁用空格剥离(对于 No Trim)。

使用 compress 指令

另一种解决方案是使用compress directive。与空格剥离相反,它直接作用于生成的输出,而不作用于模板。也就是说,它将即时调查打印的输出,而不调查创建输出的 FTL 程序。它会主动删除缩进,空行和重复的空格/制表符(有关更多信息,请阅读reference)。所以输出:

<#compress>
<#assign users = [{"name":"Joe",        "hidden":false},
                  {"name":"James Bond", "hidden":true},
                  {"name":"Julia",      "hidden":false}]>
List of users:
<#list users as user>
  <#if !user.hidden>
  - ${user.name}
  </#if>
</#list>
That's all.
</#compress>

will be:

List of users:
- Joe
- Julia
That's all.

请注意,compress完全独立于空格剥离。因此,有可能会剥离模板的空白,然后生成的输出为compress -ed。

另外,默认情况下,数据模型中有一个名为compress的用户定义方向(由于向后兼容)。这与指令相同,不同之处在于您可以选择设置single_line参数,该参数将删除所有中间的换行符。如果将上一个示例中的<#compress>...</#compress>替换为<@compress single_line=true>...</@compress>,那么将得到以下输出:

List of users: - Joe - Julia That's all.