Skip to content

Syntax Specification

大多数涉及消息的地方都可以使用消息元素,例如:

  • 消息相关的机器人 API
  • 指令和中间件的返回值
  • 本地化文件的翻译条目

本节将介绍这些地方传入字符串时所用到的语法规范。

语法

消息元素的语法与 HTML 类似,但是不完全相同。

字符

你可以在消息元素内使用任何字符。不过部分特殊字符需要转义:

原始字符转义写法
""
&&
<&lt;
>&gt;

根据上下文的不同,有些字符可能不需要被转义或使用其他的转义方式。

除此以外,你可以使用十进制或十六进制转义任何字符。例如 ' 也可以被书写成 &#39;&#x27;

标签

使用一对尖括号包裹元素名,加上可选的属性、闭合指示符,就构成了一个标签。

元素名由小写字母、数字和连字符组成,且必须以字母开头。在元素名前后添加 / 表示这是一个结束标签或自闭合标签,没有 / 符号时则表示这是一个起始标签:

  • <tag> 一个起始标签
  • </tag> 一个结束标签
  • <tag/> 一个自闭合标签

属性

起始或自闭合标签的元素名后接受可选的属性列表。每个属性必须形如以下形式:

  • key
  • key="value" (此时 value 中的 " 需要被转义)
  • key='value' (此时 value 中的 ' 需要被转义)

下面是一段示例:

html
<tag foo="1" bar/>

元素

一个元素要么是自闭合标签,要么由一对同名的起始标签和结束标签构成。元素的内容指起始标签和结束标签中间的部分,可以包含文本内容或其他元素。对于自闭合标签,元素的内容为空。下面是一段示例:

html
<parent>
  text content
  <child/>
</parent>

当存在未配对的元素时,将自动视为文本内容的一部分。文本内容前后如果存在包含换行符的连续空白字符,则会被忽略。这意味着下面两段代码是等价的:

html
<tag>
  <foo> bar
  <!-- comment -->
</tag>
html
<tag>&lt;foo&gt; bar</tag>

注释

使用成对的 <!----> 插入一段注释。注释中的部分不会被渲染。

插值

在本地化条目中我们在上述规范的基础上额外允许插值语法。插值语法通过一对花括号 {} 声明,其可能出现在属性值或元素内容中。当表示属性值时,花括号将取代引号的作用。

插值语法中的内容会被解析为一个取值表达式,其结果会被转换为字符串后插入到原始字符串中。下面是一段示例:

html
<tag foo={bar}>
  {baz}qux
</tag>

当传入 { bar: 1, baz: 2 } 时,上述消息元素将会被解析为:

html
<tag foo="1">
  2qux
</tag>

这里的取值表达式会有别于 JavaScript 表达式,它实际相当于传入对象的一个属性路径。例如当传入数组 ['a', 'b'] 时,取值表达式 {0} 将会被解析为 a (而不是 0)。

对比

与 HTML 的区别

下面列举出了一些消息元素与 HTML 语法上的区别:

  • 没有空元素,所有元素都必须手动闭合
  • 未配对的元素被视为文本内容的一部分

与 JSX 的区别

在大部分使用场景下,我们都推荐直接使用 JSX,这会拥有更好的编辑器支持。你可以对比下面三种写法,它们是等价的:

ts
import { h } from 'koishi'

ctx.middleware((session) => {
  return '你好呀,' + h('at', { id: session.userId })
})
ts
ctx.middleware((session) => {
  return `<>
    你好呀,
    <at id="${session.userId}"/>
  </>`
})
tsx
ctx.middleware((session) => {
  return <>
    你好呀,
    <at id={session.userId}/>
  </>
})

而在本地化条目中,你将无法使用 JSX,此时就需要使用带插值的消息元素了。例如:

yaml
welcome: 你好呀,<at id={userId}/>
tsx
ctx.middleware((session) => {
  return session.text('welcome', session)
})

下面列举出了一些插值的消息元素与 JSX 语法上的区别:

  • 使用 <!----> 作为注释,而不是 {/**/}
  • {} 内只能是取值表达式,而不能是任意 JavaScript 表达式或其他元素