mstch空白控制完全指南:Standalone行规则与Partial前缀如何影响输出
【免费下载链接】mstchmstch is a complete implementation of {{mustache}} templates using modern C++项目地址: https://gitcode.com/gh_mirrors/ms/mstch
mstch 是一个用现代 C++ 实现的 {{mustache}} 模板引擎,完整遵循 Mustache 规范 v1.1.3(含 lambda 扩展)。它的空白控制是输出排版最容易被忽视的环节:独立的标签行会被自动删除(Standalone 行规则),而独占一行的 partial 标签则会把行首空白作为缩进前缀注入到子模板内容中。本文带你快速搞懂这两条规则,并附常见坑位排查清单。
一、为什么 Mustache 模板的空白最难调
在 HTML 这类对空白敏感的格式里,模板标签(如{{name}}、{{#section}})往往各自独占一行。如果渲染器不处理这些"纯标签行",输出里就会混入一堆多余空行。
mstch 在模板解析完成后统一执行strip_whitespace()处理,相关实现位于 src/template_type.cpp 中的strip_whitespace与store_prefixes两个函数(声明见 src/template_type.hpp)。
一句话概括它的策略:
逐行扫描,凡是"只含标签 + 空白"的行,整行(连同行首行尾空白)从输出中抹掉;含任何非空白普通文本的行,则原样保留。
二、Standalone 行规则:哪些行会被删除
判定标准(3 个条件)
一行会被整行删除,当且仅当:
- 这一行里至少有一个标签(section、partial、注释、分隔符等均算);
- 这一行没有任何非空白的普通文本(哪怕一个字母都不行);
- 删除时连行首缩进和行尾换行一起吞掉。
对应测试用例 test/data/two_sections.mustache:
{{#foo}} {{/foo}} {{#bar}} {{/bar}}四个标签各自独占一行,全部命中规则 → 这四行整体消失,不会留下空行。同类场景可参考 test/data/empty_sections.mustache:{{#foo}}{{/foo}}foo{{#bar}}{{/bar}}中两个空 section 行被删,输出只剩foo。
一旦混入普通文本,规则立即失效
这是新手最容易踩的坑。看 test/data/disappearing_whitespace.mustache:
{{#bedrooms}}{{total}}{{/bedrooms}} BED这一行里有BED这个普通文本,所以不会被 Standalone 规则处理,标签与BED之间的结构原样保留,输出为1 BED。
再看 test/data/bug_11_eating_whitespace.mustache:
{{tag}} foo行首的{{tag}}后面跟着foo(非空白文本),整行不算"纯标签行",不会被删除——输出是yo foo,foo前面的空格也保留了。这解释了历史上 issue 11 "吞空白"的边界:只有当标签行上再无任何普通字符时,行才会整体消失。
普通文本之间的空白一律保留
Standalone 规则只动"纯标签行"。模板里正常的段落文本、标签之间的空行会被原样输出。test/data/whitespace.mustache 中两个标签之间的两个空行,在 test/data/whitespace.txt 的输出里原封不动:
Hello <两个空行> World.三、Partial 前缀规则:缩进如何"传染"
当{{> partial}}标签独占一行、且行首有缩进时,mstch 会执行一条特殊逻辑:把标签前的那段空白存为 partial 前缀,子模板渲染后每一行都会自动加上这个缩进。
这正是store_prefixes()的工作(见 src/template_type.cpp 中store_prefixes函数):识别"前一个 token 是纯空白、当前 token 是 partial"的情形,并记录该空白。
以 test/data/partial_template.mustache 为例:
<h1>{{title}}</h1> {{>partial}} Again, {{again}}!子模板 test/data/partial_template.partial 的内容会被原样插入,标签所在行本身因 Standalone 规则消失。最终输出(test/data/partial_template.txt):
<h1>Welcome</h1> Again, Goodbye!📌要点:partial 标签行的缩进决定了子模板的"基准缩进"。如果你把{{> partial}}缩进 4 个空格,子模板的每一行输出都会自动带上 4 空格前缀,无需在子模板里手写缩进——这对维护 HTML 模板的整洁非常有用。
而 test/data/partial_whitespace.mustache 则展示了另一个细节:{{ greeting }}这类标签内部的多余空格只影响标签解析,不参与 Standalone 判定;{{> partial }}独占一行且行首无空白时,子模板按原始缩进插入。
四、实战排查清单:输出空白不对怎么办
| 现象 | 原因 | 参考用例 |
|---|---|---|
| 模板里的空行没了 | 该行只有标签,被 Standalone 规则整行删除 | test/data/two_sections.mustache |
| 标签行没被删,还带了奇怪空格 | 行上混入了普通文本(哪怕一个空格后的字母) | test/data/disappearing_whitespace.mustache |
| 段落间的空行消失 | 并非 Standalone 行为,检查是否被其他模板嵌套吞掉 | test/data/whitespace.mustache |
| 子模板缩进与预期不符 | partial 标签行首空白被当作前缀应用到子模板每行 | test/data/partial_template.partial |
3 步自检法:
- 找出输出中"丢失/多出"空白所在的那一行,回模板确认该行是否含非空白普通文本;
- 若该行是纯标签行——它本就该被删,想让空白保留,把标签和文本放在同一行;
- 若涉及
{{> partial}},检查标签行首缩进,它就是子模板的自动前缀。
五、小结
- Standalone 行:纯标签行整行删除(含行首行尾空白),核心逻辑在
src/template_type.cpp的strip_whitespace(); - Partial 前缀:独占一行的 partial 标签,其行首空白成为子模板的自动缩进,逻辑在
store_prefixes(); - 想让标签行的空白保留,唯一办法是让该行出现普通文本,与标签同行;
- 模板的公共 API 入口在 include/mstch/mstch.hpp,所有空白行为都发生在
render内部的模板解析阶段,对调用者透明。
掌握这两条规则,你的 mstch 模板输出就能做到"所见即所得"。
【免费下载链接】mstchmstch is a complete implementation of {{mustache}} templates using modern C++项目地址: https://gitcode.com/gh_mirrors/ms/mstch
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考