协议规范 · v1.0

给 HTML 装一个
语义插座

v1.0 MIT License AI-Native设计 IR建模范式

data-semantic 是面向 AI 时代的声明式数据绑定协议。纯 HTML、零 JS 侵入,让 UI 结构与数据获取逻辑彻底解耦 —— 为 AI 生成代码而生。

模板
数据
翻译结果
更多示例→
<h1 data-semantic="page.title"></h1>
<div data-semantic-list="page.chapters">
  <div>
    <p data-semantic=".name"></p>
    <a data-semantic-href=".url"></a>
  </div>
</div>
data
{
  "page": {
    "title": "Data-Semantic 协议规范 v1.0",
    "chapters": [
      { "name": "基本概念", "url": "https://x.com" },
      { "name": "协议原文", "url": "https://y.com" }
    ]
  }
}
runtime
compiler
npm i data-semantic
import { DataSemantic } from 'data-semantic';

// 读取数据
DataSemantic.render(data);
npm i data-semantic-compiler
import { compile } from 'data-semantic-compiler';

// 读取模板代码
// 读取数据
const result = compile(template, data);
<h1 data-semantic="page.title">Data-Semantic 协议规范 v1.0</h1>
<div data-semantic-list="page.chapters">
  <div>
    <p data-semantic=".name">基本概念</p>
    <a data-semantic-href=".url">https://x.com</a>
  </div>
  <div>
    <p data-semantic=".name">协议原文</p>
    <a data-semantic-href=".url">https://y.com</a>
  </div>
</div>

data-semantic 属性依然保留在源码中 —— 这是「保留语义声明」的要求。

01 · 范式

先定 Schema,再谈 UI

AI 更擅长语义建模。data-semantic主张先确定领域性的、语义性的IR数据结构,UI侧按schema声明语义槽位,数据侧提供实例数据,运行时 / 编译器完成确定性翻译 —— 建模、UI、数据、翻译器四者分离。

01 · 领域 IR 建模

先确定要显示什么

只需要标题和章节元信息,就用极简 schema 描述数据结构。Schema 一旦确定,语义与寻址关系随之确定。

{
  page: {
    title,        // 页面标题
    chapters: [{  // 章节数组
      name,       // 章节名称
      url         // 章节地址
    }]
  }
}
02 · UI 声明

按 schema 声明语义槽位

两个核心概念:属性决定渲染到哪、怎么渲染;Key 决定渲染什么、怎么寻址。

<h1 data-semantic="page.title"></h1>
<div data-semantic-list="page.chapters">
  <div>
    <p data-semantic=".name"></p>
    <a data-semantic-href=".url"></a>
  </div>
</div>
03 · 数据准备

基于同一份 IR 准备实例

与 schema 结构完全对应的实例数据,供运行时 / 编译器在翻译阶段寻址取值。

{
  "page": {
    "title": "Data-Semantic 协议规范 v1.0",
    "chapters": [
      { "name": "基本概念", "url": "https://x.com" },
      { "name": "协议原文", "url": "https://y.com" }
    ]
  }
}
04 · 翻译

结合声明与数据,完成 DOM 翻译

Runtime / Compiler 进行协议运算,翻译范围取决于寻址命中量,未命中部分保持不变。

<h1 data-semantic="page.title">Data-Semantic 协议规范 v1.0</h1>
<div data-semantic-list="page.chapters">
  <div>
    <p data-semantic=".name">基本概念</p>
    <a data-semantic-href=".url">https://x.com</a>
  </div></div>

这种建模、UI、数据、翻译器分离的范式,能够带来巨大的灵活性:
* UI生成复杂度低。
* UI 与数据可双端独立单测,几乎不需要集成测试,测试成本趋近于零。
* 渲染后 data-semantic 属性原样保留,页面结构天然携带可对照的数据语义,为知识源主动向外暴露语义,也为AI精准分析语义,或三方平台提供语义增强,提供了自动化基础。。

02 · 声明和翻译规则

四大声明,正交组合

目前支持四大类语义声明方式(内容绑定、属性绑定、可见性绑定、列表容器),正交设计,可自由叠加。

通用原则 · 正交组合
声明对应操作
data-semantic={key}Node.textContent
data-semantic-{attr}={key}Element.setAttribute()
data-semantic-display={key}Element.style.display
data-semantic-list={key}列表容器(innerHTML 为模板,n 次实例化)

单个元素可以包含多个相互独立的声明:

<a
  data-semantic="linkText"
  data-semantic-href="linkUrl"
  data-semantic-title="linkTooltip"
  data-semantic-display="showLink"
></a>
通用原则 · 属性透传规则

任何非 data-semantic 或非 data-semantic-* 的属性,都将按原样透传至渲染输出中,不参与键解析。

<span data-semantic-data-role="user.role"></span>  <!-- ✅ 白名单内,执行语义翻译 -->
<span data-semantic-role="user.role"></span>     <!-- 透传,不做处置 -->
<span semantic-role="user.role"></span>          <!-- 透传,不做处置 -->
WHITELIST 仅白名单内的 10 种 data-semantic-* 属性会被 runtime 处理,其余自定义 data 属性一律忽略。
SECURITY 事件处理器(onclick 等)、style、全局标识符、iframe src 等内联脚本类目标均不在白名单内。
通用原则 · 翻译模式

实际的翻译范围取决于传入的数据及寻址命中量,列表容器节点和普通叶子节点的规则有所不同。

  • 叶子增量:只变动当次传入数据命中的范围,未命中部分保持不变。
  • 列表全量:如果列表此前有 2 项,下一次渲染只传入 1 项,那么整个 list 节点会重新渲染,只剩下一项。

示例 — 模板:

<div data-semantic-list="answer">
  <p data-semantic="."></p>
</div>

第一次渲染 — 传入 3 项:

DataSemantic.render({ answer: ["不要回答!", "不要回答!", "不要回答!"] });
<div data-semantic-list="answer">
  <p data-semantic=".">不要回答!</p>
  <p data-semantic=".">不要回答!</p>
  <p data-semantic=".">不要回答!</p>
</div>

第二次渲染 — 只传入 1 项,整个列表重新渲染:

DataSemantic.render({ answer: ["不要回答啊!"] });
<div data-semantic-list="answer">
  <p data-semantic=".">不要回答啊!</p>
</div>
1 · 内容绑定

最基础的声明能力,将解析出的值渲染到元素的 textContent

<h1 data-semantic="page.title"></h1>
解析值渲染行为
有效值设置 textContent(执行 toString)
undefined清空元素内容。开发模式下发出警告。
null清空元素内容。
2 · 属性绑定

每个 data-semantic-{attr} 都会绑定到对应的 HTML 属性。

<img data-semantic-src="user.avatar" data-semantic-alt="user.name">
<span data-semantic-data-role="user.role"></span>
属性白名单

翻译阶段,仅允许翻译以下白名单属性:

属性绑定 DOM用途示例
data-semantic-placeholderplaceholder输入框占位符<input data-semantic-placeholder="…">
data-semantic-valuevalue表单初始值(单向)<input data-semantic-value="…">
data-semantic-titletitle鼠标悬停提示<button data-semantic-title="…">
data-semantic-altalt图片替代文本<img data-semantic-alt="…">
data-semantic-srcsrc动态资源链接<img/video/iframe data-semantic-src="…">
data-semantic-hrefhref动态跳转地址<a data-semantic-href="…">
data-semantic-aria-labelaria-label无障碍标签<button data-semantic-aria-label="…">
data-semantic-aria-descriptionaria-description无障碍详细描述<div role="tooltip" …>
data-semantic-contentcontentmeta 动态内容<meta data-semantic-content="…">
data-semantic-data-*data-*(透传)自定义 data 属性data-semantic-data-user-id="…"
数据解析
解析值渲染行为
undefined移除该属性。开发模式下发出警告。
null移除该属性。
有效值设置属性值(toString)。白名单外属性不做处理。
3 · 可见性绑定

data-semantic-display 是协议中唯一的样式相关绑定,用于控制 style.display

<div data-semantic-display="showLogin"></div>
解析值style.display 结果
布尔值 true''(显示)
布尔值 false'none'(不显示)
逻辑假值("" / 0 / null / undefined / "false")'none'
逻辑真值字符串(以上 5 种之外的)''(显示)
FALSE 字符串形式的 "false" 归入逻辑假值,与布尔 false 效果一致。
NO CSS element.style.display = '' 的语义是移除内联 display 声明,不影响 class 层叠规则。
4 · 列表容器

data-semantic-list 用于声明列表容器,{key} 对应解析为数据中的一个数组。容器元素本身不会被克隆,其 innerHTML 即为列表项模板。

<div data-semantic-list="page.chapters">
  <h2 data-semantic=".name"></h2>
  <div data-semantic-list=".items">
    <span data-semantic=".title"></span>
    <span data-semantic="page.title"></span>  <!-- 绝对键,跳出上下文 -->
  </div>
</div>
数据值渲染行为
数组渲染模板的 i 个克隆实例
空数组 []清空容器子节点,不报错
undefined(键缺失)保持原始模板 DOM 不变,发出警告
null清空容器子节点,发出警告
非数组(字符串、对象等)违反协议 — check 报错,运行时发出警告并跳过渲染
CONTEXT 每个克隆出的列表项都会建立新的语义上下文:相对键相对于 {listKey}[i] 解析,嵌套列表创建嵌套上下文,绝对键可绕过上下文。
03 · Key 寻址与命名

绝对寻址 vs 相对寻址

相对寻址只能由 data-semantic-list 提供上下文,杜绝深层上下文栈带来的语义歧义。

绝对寻址

page.title
page.chapters[0].name

从数据根节点开始解析,等价于 dataRoot.page.title

相对寻址

.name
[0].name

必须以 .[ 开头,相对于最近的 data-semantic-list 上下文。

位置上下文语义
根层级(无列表祖先)数据根节点 dataRoot
列表项内部{listKey}[i]
嵌套列表项内部最内层的 {listKey}[i]
命名规范

UI 侧寻址 key 仅允许 base64URL 字符集 + . [ ];数据侧字段 key 严禁出现 . [ ] ? 四个符号。

✓ 正确
"a-a_b": "..."
data-semantic="biology.animal.bear"
✗ 错误
"aa.b[": "包含特殊符号"
"aa.?": "与可选链冲突"
04 · 容错规则

容错规则

协议支持增量翻译、流式翻译,允许只传入部分数据。每一级寻址默认自带 ?. 效果:链路中任意环节为 undefined / null 时不报错,保持现状;类型不匹配时仍会正常报错。

第一次传入
{ "page": { "title": "…" } }

page.chapters 寻址不到,保持原状,不报错

第二次传入
{ "page": { "chapters": […] } }

此次命中 chapters,触发列表翻译

05 · 框架层要求

开放语义网络

data-semantic 不只是渲染工具,也是一份对三方开放的语义声明 —— 框架实现必须保证以下两点。

自动注入协议头

<head>

Runtime 首次渲染、Compiler 编译产出时,都必须自动向页面 <head> 注入协议声明,向三方开放本页面遵循的语义化标记。

<meta name="data-semantic" content="1.0" />

保留语义声明

不可剥离

编译后的 UI 必须继续保留 data-semantic 属性;

✓ 正确
<p data-semantic="content">这是内容</p>
✗ 错误
<p>这是标题</p>
语义声明被剥离,三方无法分析
06 · 运行时与编译器要求

安全边界是协议的一部分

数据必须是纯JSON;以下模式一律视为语义污染,check 阶段明确拒绝。

事件处理函数

data-semantic-onclick 等一律禁止

样式注入

data-semantic-style 禁止,display 除外

非纯 JSON 数据

dataRoot 必须是 Plain Object,禁止根数组

危险协议注入

iframe data-semantic-src 禁止 javascript: / data: / vbscript:

inspect(template)

返回语义节点扁平数组:tag / key / type / selector / line

check(template, data)

返回 valid / errors(违反协议)/ warnings(数据缺失)

07 · 一致性测试

Runtime 与 Compiler,输出必须一致

每个测试用例是一个独立目录,Runtime runner 与 Compiler runner 各自执行,并与 expected.html 比对。

01绝对键绑定
02相对键绑定
03数字键绑定(方括号)
04列表渲染(基础)
05空列表
06带相对键的嵌套列表
07带绝对键的列表(跳出上下文)
08属性绑定
09数据缺失(undefined / null)
10多重绑定
11非数组列表数据源(反向)
12禁止模式(反向)
template.html — HTML 模板
data.json — 输入数据
expected.html — 预期渲染输出