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>
{ "page": { "title": "Data-Semantic 协议规范 v1.0", "chapters": [ { "name": "基本概念", "url": "https://x.com" }, { "name": "协议原文", "url": "https://y.com" } ] } }
import { DataSemantic } from 'data-semantic'; // 读取数据 DataSemantic.render(data);
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 属性依然保留在源码中 —— 这是「保留语义声明」的要求。
AI 更擅长语义建模。data-semantic主张先确定领域性的、语义性的IR数据结构,UI侧按schema声明语义槽位,数据侧提供实例数据,运行时 / 编译器完成确定性翻译 —— 建模、UI、数据、翻译器四者分离。
只需要标题和章节元信息,就用极简 schema 描述数据结构。Schema 一旦确定,语义与寻址关系随之确定。
{
page: {
title, // 页面标题
chapters: [{ // 章节数组
name, // 章节名称
url // 章节地址
}]
}
}
两个核心概念:属性决定渲染到哪、怎么渲染;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>
与 schema 结构完全对应的实例数据,供运行时 / 编译器在翻译阶段寻址取值。
{
"page": {
"title": "Data-Semantic 协议规范 v1.0",
"chapters": [
{ "name": "基本概念", "url": "https://x.com" },
{ "name": "协议原文", "url": "https://y.com" }
]
}
}
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精准分析语义,或三方平台提供语义增强,提供了自动化基础。。
目前支持四大类语义声明方式(内容绑定、属性绑定、可见性绑定、列表容器),正交设计,可自由叠加。
| 声明 | 对应操作 |
|---|---|
| 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> <!-- 透传,不做处置 -->
data-semantic-* 属性会被 runtime 处理,其余自定义 data 属性一律忽略。onclick 等)、style、全局标识符、iframe src 等内联脚本类目标均不在白名单内。实际的翻译范围取决于传入的数据及寻址命中量,列表容器节点和普通叶子节点的规则有所不同。
示例 — 模板:
<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>
最基础的声明能力,将解析出的值渲染到元素的 textContent。
<h1 data-semantic="page.title"></h1>
| 解析值 | 渲染行为 |
|---|---|
| 有效值 | 设置 textContent(执行 toString) |
| undefined | 清空元素内容。开发模式下发出警告。 |
| null | 清空元素内容。 |
每个 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-placeholder | placeholder | 输入框占位符 | <input data-semantic-placeholder="…"> |
| data-semantic-value | value | 表单初始值(单向) | <input data-semantic-value="…"> |
| data-semantic-title | title | 鼠标悬停提示 | <button data-semantic-title="…"> |
| data-semantic-alt | alt | 图片替代文本 | <img data-semantic-alt="…"> |
| data-semantic-src | src | 动态资源链接 | <img/video/iframe data-semantic-src="…"> |
| data-semantic-href | href | 动态跳转地址 | <a data-semantic-href="…"> |
| data-semantic-aria-label | aria-label | 无障碍标签 | <button data-semantic-aria-label="…"> |
| data-semantic-aria-description | aria-description | 无障碍详细描述 | <div role="tooltip" …> |
| data-semantic-content | content | meta 动态内容 | <meta data-semantic-content="…"> |
| data-semantic-data-* | data-*(透传) | 自定义 data 属性 | data-semantic-data-user-id="…" |
| 解析值 | 渲染行为 |
|---|---|
| undefined | 移除该属性。开发模式下发出警告。 |
| null | 移除该属性。 |
| 有效值 | 设置属性值(toString)。白名单外属性不做处理。 |
data-semantic-display 是协议中唯一的样式相关绑定,用于控制 style.display。
<div data-semantic-display="showLogin"></div>
| 解析值 | style.display 结果 |
|---|---|
| 布尔值 true | ''(显示) |
| 布尔值 false | 'none'(不显示) |
| 逻辑假值("" / 0 / null / undefined / "false") | 'none' |
| 逻辑真值字符串(以上 5 种之外的) | ''(显示) |
"false" 归入逻辑假值,与布尔 false 效果一致。element.style.display = '' 的语义是移除内联 display 声明,不影响 class 层叠规则。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 报错,运行时发出警告并跳过渲染 |
{listKey}[i] 解析,嵌套列表创建嵌套上下文,绝对键可绕过上下文。相对寻址只能由 data-semantic-list 提供上下文,杜绝深层上下文栈带来的语义歧义。
从数据根节点开始解析,等价于 dataRoot.page.title。
必须以 . 或 [ 开头,相对于最近的 data-semantic-list 上下文。
| 位置 | 上下文语义 |
|---|---|
| 根层级(无列表祖先) | 数据根节点 dataRoot |
| 列表项内部 | {listKey}[i] |
| 嵌套列表项内部 | 最内层的 {listKey}[i] |
UI 侧寻址 key 仅允许 base64URL 字符集 + . [ ];数据侧字段 key 严禁出现 . [ ] ? 四个符号。
协议支持增量翻译、流式翻译,允许只传入部分数据。每一级寻址默认自带 ?. 效果:链路中任意环节为 undefined / null 时不报错,保持现状;类型不匹配时仍会正常报错。
{ "page": { "title": "…" } }
page.chapters 寻址不到,保持原状,不报错
{ "page": { "chapters": […] } }
此次命中 chapters,触发列表翻译
data-semantic 不只是渲染工具,也是一份对三方开放的语义声明 —— 框架实现必须保证以下两点。
Runtime 首次渲染、Compiler 编译产出时,都必须自动向页面 <head> 注入协议声明,向三方开放本页面遵循的语义化标记。
<meta name="data-semantic" content="1.0" />
编译后的 UI 必须继续保留 data-semantic 属性;
数据必须是纯JSON;以下模式一律视为语义污染,check 阶段明确拒绝。
data-semantic-onclick 等一律禁止
data-semantic-style 禁止,display 除外
dataRoot 必须是 Plain Object,禁止根数组
iframe data-semantic-src 禁止 javascript: / data: / vbscript:
返回语义节点扁平数组:tag / key / type / selector / line
返回 valid / errors(违反协议)/ warnings(数据缺失)
每个测试用例是一个独立目录,Runtime runner 与 Compiler runner 各自执行,并与 expected.html 比对。