六维教程

Web Clipper 过滤器与模板逻辑

上一篇讲了变量怎么取值,取回来的原始数据往往还要再加工,比如把日期换个格式、把数组拼成列表、没取到作者时给个兜底文案。这些加工靠过滤器和模板逻辑完成。

这套模板语法叫 Knap,是 Obsidian 开源的模板语言。内容比较多,先收藏,写模板时当手册翻。

过滤器

语法

竖线接过滤器名,冒号传参数,可以链式串多个:

{{title|lower|replace:" ":"-"}}
{{published|date:"YYYY-MM-DD"}}

字符串参数用引号包住,多个参数用逗号分隔。

日期

过滤器 作用 示例
date 格式化日期,默认输出 YYYY-MM-DD {{published|date:"YYYY年MM月DD日"}}
date_modify 日期加减 {{date|date_modify:"+1 day"}}、{{date|date_modify:"-2 weeks"}}
duration 把 ISO 8601 时长或秒数转成 HH:mm:ss {{duration|duration:"mm:ss"}}

几点说明:

  • date 支持第二个参数指定输入格式,{{published|date:"YYYY-MM-DD","MM/DD/YYYY"}}。
  • date_modify 的单位支持 year、month、week、day、hour、minute、second,单复数都行。
  • duration 适合处理视频时长这类数据,不指定格式时超过一小时输出 HH:mm:ss,否则输出 mm:ss。

文本转换与大小写

过滤器 作用 示例
lower / upper 全小写 / 全大写 {{title|lower}}
capitalize 首字母大写 {{author|capitalize}}
title 每个单词首字母大写 {{title|title}}
camel / pascal 驼峰 / 帕斯卡命名 {{title|camel}}
kebab / snake 连字符 / 下划线命名 {{title|kebab}}
uncamel 把驼峰拆回空格分隔 {{var|uncamel}}
trim 去掉首尾空白 {{var|trim}}
replace 替换文本,支持正则 见下
safe_name 转成合法文件名 {{title|safe_name}}
decode_uri URI 解码 {{var|decode_uri}}
unescape 反转义 HTML 实体 {{var|unescape}}

replace 是最常用的,支持多组替换连续执行,也支持斜杠包正则:

{{title|replace:"草稿 - ":""}}
{{url|replace:"https://":"","/":""}}
{{title|replace:"/\\s+/g":"-"}}

safe_name 会去掉 Windows、macOS、Linux 文件名里的非法字符和 Obsidian 的特殊字符(# [ ] | ^),结果为空时返回 Untitled。可以传参数 "windows"、"mac"、"linux" 按平台规则处理,不传则用最严格的合集。写笔记名称时建议都过一遍它。

文本格式化

过滤器 作用 示例
blockquote 每行加 > 变引用块 {{content|blockquote}}
callout 包成 Obsidian Callout {{content|callout:"tip","小提示"}}
footnote 数组转成脚注定义列表 {{footnotes|footnote}}
image URL 转 Markdown 图片 {{image|image:"封面图"}}
link URL 转 Markdown 链接 {{url|link:"原文"}}
wikilink 转 Obsidian 双链 {{author|wikilink}}
list 数组转列表 {{tags|list:"numbered"}}
table 数组或对象转 Markdown 表格 {{rows|table}}
fragment_link 给高亮附加原文定位链接 见下

几点说明:

  • callout 第三个参数传 "true" 生成默认折叠的 Callout,"false" 生成默认展开的。
  • list 的参数有 numbered(有序)、task(任务列表)、numbered-task,不传是无序列表,嵌套数组会自动缩进。
  • wikilink 传参数作为别名,{{title|wikilink:"别名"}} 输出 [[标题|别名]]。
  • fragment_link 会在文本后追加一个带 #:~:text= 定位参数的链接,点开能直接跳到原文对应位置,配合 {{highlights}} 使用效果最好。

数字

过滤器 作用 示例
calc 四则运算 {{words|calc:"+100"}}、{{price|calc:"*0.8"}}
length 字符串长度、数组或对象的条目数 {{tags|length}}
number_format 千分位格式化 {{price|number_format:2,".",","}}
round 四舍五入,参数为小数位数 {{rating|round:1}}

calc 的运算符支持 + - * / ^ **(后两个都是乘方)。number_format 的三个参数依次是小数位数、小数点符号、千分位符号。

HTML 处理

这组过滤器处理 {{contentHtml}}、{{selectorHtml:...}} 这类 HTML 格式的变量。

过滤器 作用 示例
markdown HTML 转 Markdown {{selectorHtml:#main|markdown}}
remove_html 删除匹配选择器的元素(含内容) {{contentHtml|remove_html:".ads,footer"}}
remove_tags 删除指定标签但保留内容 {{contentHtml|remove_tags:"span,font"}}
remove_attr 删除指定属性 {{contentHtml|remove_attr:"class,style"}}
replace_tags 把一种标签换成另一种 {{contentHtml|replace_tags:"b:strong","i:em"}}
strip_tags 去掉所有 HTML 标签,传参则只保留指定标签 {{contentHtml|strip_tags:"p,a"}}
strip_attr 去掉所有属性,传参则只保留指定属性 {{contentHtml|strip_attr:"href"}}
strip_md 去掉 Markdown 语法只留纯文本 {{content|strip_md}}
html_to_json HTML 转 JSON 结构,方便再加工 {{contentHtml|html_to_json}}

处理页面时推荐一条链,先用选择器取范围,再清理,最后转 Markdown:

{{selectorHtml:#main|remove_html:".share,.related"|strip_attr|markdown}}

数组与对象

{{highlights}}、{{schema:author[*].name}}、多匹配的 selector 变量,拿到的都是数组,这组过滤器专门处理。

过滤器 作用 示例
first / last 第一项 / 最后一项 {{authors|first}}
join 拼成字符串,默认逗号分隔 {{tags|join:", "}}
map 逐项提取属性或用箭头函数变换 见下
merge 往数组追加元素 {{tags|merge:"读书笔记"}}
nth 按位置筛选,CSS nth 风格 {{items|nth:2}}、{{items|nth:"2n"}}
object 对象转键数组、值数组或键值对数组 {{obj|object:"keys"}}
reverse 倒序 {{items|reverse}}
slice 截取片段,和 JS 的 slice 一样 {{items|slice:0,5}}
split 字符串拆成数组 {{keywords|split:","}}
template 按模板串逐项渲染 见下
unique 去重 {{tags|unique}}

map 有两种写法。属性路径写法适合对象数组,箭头函数写法更灵活:

{{schema:author[*]|map:"name"|join:", "}}
{{highlights|map: item => item.text|join:"\n\n"}}

template 把数组里每个对象套进一段模板,用 ${属性} 占位,条目之间空一行:

{{highlights|template:"${text}\n- [[${created}]]"}}

模板逻辑

模板逻辑用大括号加百分号的标签语法,写在模板正文中。注意下面所有示例都要整段放进模板里,标签不能拆开用。

条件判断

变量存在才输出对应内容:

{% if author %}
作者: {{author}}
{% endif %}

支持 elseif 和 else 多分支:

{% if domain contains "zhihu" %}
来源: 知乎
{% elseif domain contains "weixin" %}
来源: 公众号
{% else %}
来源: {{domain}}
{% endif %}

比较运算符有 ==、!=、>、<、>=、<=、contains(字符串包含或数组成员)。逻辑运算符有 and、or、not,也可以用 &&、||、!,支持括号分组。

单独写一个变量时是真假判断。空字符串、空数组、0、false、null 都算假,其余都算真。

变量赋值

set 标签可以在模板里造新变量,后续直接用:

{% set slug = title|lower|replace:" ":"-" %}
文件名: {{slug}}

可以赋其他变量、字面量、过滤器处理结果,也可以是选择器抓取的结果:

{% set comments = selector:.comment %}

回退值

两个问号给空值准备兜底文案:

作者: {{author ?? "未知"}}

可以连着写,依次尝试:

{{author ?? schema:author.name ?? "未知"}}

注意优先级,过滤器比 ?? 先执行。{{title|upper ?? "UNTITLED"}} 是先做大写转换再判断空不空。想给兜底值也加过滤器,要用括号把意图分开写。

循环

for 标签遍历数组:

{% for item in schema:author %}
- {{item.name}}
{% endfor %}

循环可以直接遍历 schema 数组、选择器结果,或先 set 再遍历。循环内部有个 loop 对象:

属性 含义
loop.index 当前序号,从 1 开始
loop.index0 当前序号,从 0 开始
loop.first / loop.last 是否第一项 / 最后一项
loop.length 总条数

数组按下标取元素用方括号,比如两个平行数组配合输出:

{% set transcripts = selector:.transcript-text %}
{% set timestamps = selector:.timestamp %}
{% for line in transcripts %}
{{timestamps[loop.index0]}} - {{line}}
{% endfor %}

循环可以嵌套,也能和条件判断混用。

求值顺序

模板分两步处理,顺序很重要:

  1. 先执行全部模板逻辑,条件、循环、赋值和普通变量在这一步完成。
  2. 再把 prompt 变量发给 Interpreter 的大模型,拿回结果填进去。

所以可以用模板逻辑拼接出 prompt 变量的内容,但 prompt 变量的结果不能再参与条件和循环。

速查卡片

主题 要点
过滤器 竖线串联,冒号传参,字符串参数加引号
高频 date、replace、safe_name、join、map、markdown
条件 if 标签,支持 contains 和 and/or/not
兜底 ??,可链式,过滤器先执行
循环 for 标签,loop 对象拿下标和首尾状态
顺序 模板逻辑先于 prompt 变量执行

下一篇讲 Web Clipper 最好玩也最贵的功能,用自然语言驱动大模型的 Interpreter,以及常见问题的排查方法。

上一篇
Web Clipper 模板与变量
下一篇
Web Clipper Interpreter 与常见问题